├── .gitignore ├── Cartfile ├── Cartfile.resolved ├── ImageCrawler.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── cc.xcuserdatad │ │ ├── IDEFindNavigatorScopes.plist │ │ └── xcdebugger │ │ └── Expressions.xcexplist ├── xcshareddata │ └── xcschemes │ │ └── CrawlerTunnelProvider.xcscheme └── xcuserdata │ └── cc.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── ImageCrawler.xcscheme │ └── xcschememanagement.plist ├── ImageCrawler ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon-1.appiconset │ │ ├── Artboard@2x.png │ │ ├── Artboard@3x.png │ │ ├── Contents.json │ │ ├── Icon.png │ │ ├── icon_20pt.png │ │ ├── icon_20pt@2x-1.png │ │ ├── icon_20pt@2x.png │ │ ├── icon_20pt@3x.png │ │ ├── icon_29pt.png │ │ ├── icon_29pt@2x-1.png │ │ ├── icon_29pt@2x.png │ │ ├── icon_29pt@3x.png │ │ ├── icon_40pt.png │ │ ├── icon_40pt@2x-1.png │ │ ├── icon_40pt@2x.png │ │ ├── icon_40pt@3x.png │ │ ├── icon_76pt.png │ │ ├── icon_76pt@2x.png │ │ └── icon_83.5@2x.png │ ├── Contents.json │ ├── _ionicons_svg_ios-power.imageset │ │ ├── Contents.json │ │ └── icon_29pt@2x.pdf │ ├── _ionicons_svg_md-tv.imageset │ │ ├── Contents.json │ │ └── icon_29pt@2x.pdf │ ├── first.imageset │ │ ├── Contents.json │ │ └── first.pdf │ ├── har_template.dataset │ │ ├── Contents.json │ │ └── sample.json │ └── second.imageset │ │ ├── Contents.json │ │ └── second.pdf ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── ImageCrawler.entitlements ├── Info.plist ├── Models │ └── RequestRecord.swift ├── SecondViewController.swift ├── TEstTableViewController.swift ├── Utils │ ├── DebugUtil.swift │ ├── HarProvider.swift │ ├── NetworkManager.swift │ ├── RealmUtil.swift │ └── TableSegment.swift ├── ViewControllers │ ├── DetailController.swift │ ├── HomeController.swift │ ├── HttpBodyController.swift │ ├── RecordController.swift │ ├── RequestSegmentController.swift │ ├── ResponseSegmentController.swift │ ├── SegmentController.swift │ ├── SummarySegmentController.swift │ └── SwitcherController.swift └── Views │ ├── DetailContentCell.swift │ └── RecordCell.swift ├── ImageCrawlerTests ├── ImageCrawlerTests.swift └── Info.plist ├── ImageCrawlerUITests ├── ImageCrawlerUITests.swift └── Info.plist ├── README.md ├── TunnelProvider ├── Info.plist ├── PacketTunnelProvider.swift ├── ProxyObserverFactory.swift └── TunnelProvider.entitlements ├── art ├── s1.png ├── s2.png ├── s3.png └── s4.png ├── icon.png ├── icon.sketch └── jj /.gitignore: -------------------------------------------------------------------------------- 1 | Carthage 2 | -------------------------------------------------------------------------------- /Cartfile: -------------------------------------------------------------------------------- 1 | github "onevcat/Kingfisher" ~> 4.0 2 | github "T-Pham/Switch" 3 | github "zhuhaow/NEKit" "master" 4 | github "realm/realm-cocoa" 5 | github "malcommac/SwiftDate" 6 | github "raspu/Highlightr" 7 | github "SwiftyJSON/SwiftyJSON" ~> 4.0 8 | 9 | 10 | -------------------------------------------------------------------------------- /Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "CocoaLumberjack/CocoaLumberjack" "3.4.2" 2 | github "SwiftyJSON/SwiftyJSON" "4.1.0" 3 | github "T-Pham/Switch" "2.0.1" 4 | github "lexrus/MMDB-Swift" "0.2.8" 5 | github "malcommac/SwiftDate" "4.5.1" 6 | github "onevcat/Kingfisher" "4.8.0" 7 | github "raspu/Highlightr" "2.0.1" 8 | github "realm/realm-cocoa" "v3.7.4" 9 | github "robbiehanson/CocoaAsyncSocket" "7.6.3" 10 | github "zhuhaow/NEKit" "ab592a99f6d34f80b1081a60d1f36f1d68fdda1e" 11 | github "zhuhaow/Resolver" "0.1.3" 12 | github "zhuhaow/Sodium-framework" "v1.0.10.1" 13 | github "zhuhaow/YamlSwift" "3e880fee0e68653f8304392cf0a9b7fc4b376a38" 14 | github "zhuhaow/tun2socks" "0.6.1" 15 | -------------------------------------------------------------------------------- /ImageCrawler.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 420446AF20DA3F6300ABDF31 /* RecordController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 420446AE20DA3F6300ABDF31 /* RecordController.swift */; }; 11 | 420446B120DA45A800ABDF31 /* RecordCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 420446B020DA45A800ABDF31 /* RecordCell.swift */; }; 12 | 421EB72920D8CF5A00B05640 /* RealmSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 421EB72820D8CF5A00B05640 /* RealmSwift.framework */; }; 13 | 421EB72B20D8CF8B00B05640 /* Realm.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 421EB72A20D8CF8B00B05640 /* Realm.framework */; }; 14 | 421EB72E20D8D26F00B05640 /* RequestRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 421EB72D20D8D26F00B05640 /* RequestRecord.swift */; }; 15 | 423838E220E63CC8008AE7A8 /* HarProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 423838E120E63CC8008AE7A8 /* HarProvider.swift */; }; 16 | 423838E420E6FBCB008AE7A8 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 423838E320E6FBCB008AE7A8 /* SwiftyJSON.framework */; }; 17 | 4256260B20DFAF320033E0A8 /* DebugUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4256260A20DFAF320033E0A8 /* DebugUtil.swift */; }; 18 | 428CF3BB20DB4CC6009D90A2 /* HomeController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 428CF3BA20DB4CC6009D90A2 /* HomeController.swift */; }; 19 | 428CF3C120DB90F8009D90A2 /* DetailController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 428CF3C020DB90F8009D90A2 /* DetailController.swift */; }; 20 | 428CF3C420DB97A1009D90A2 /* DetailContentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 428CF3C320DB97A1009D90A2 /* DetailContentCell.swift */; }; 21 | 42A18C3B20E99E1E00DD4AA5 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42A18C3A20E99E1E00DD4AA5 /* NetworkExtension.framework */; }; 22 | 42A18C3C20E99ED400DD4AA5 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42A18C3A20E99E1E00DD4AA5 /* NetworkExtension.framework */; }; 23 | 42AB61B020E0ED8F007EEA69 /* SummarySegmentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42AB61AF20E0ED8F007EEA69 /* SummarySegmentController.swift */; }; 24 | 42AB61B620E10BF1007EEA69 /* SwiftDate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42AB61B520E10BF1007EEA69 /* SwiftDate.framework */; }; 25 | 42AB61B820E1161B007EEA69 /* RequestSegmentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42AB61B720E1161B007EEA69 /* RequestSegmentController.swift */; }; 26 | 42AB61BC20E2141A007EEA69 /* HttpBodyController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42AB61BB20E2141A007EEA69 /* HttpBodyController.swift */; }; 27 | 42AB61BE20E218B9007EEA69 /* ResponseSegmentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42AB61BD20E218B9007EEA69 /* ResponseSegmentController.swift */; }; 28 | 42AB61C020E231F2007EEA69 /* Highlightr.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42AB61BF20E231F2007EEA69 /* Highlightr.framework */; }; 29 | 42AB61C220E2473B007EEA69 /* SwitcherController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42AB61C120E2473B007EEA69 /* SwitcherController.swift */; }; 30 | 42AB61E220E4C3D9007EEA69 /* NEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42E68EC320D3177900E715DE /* NEKit.framework */; }; 31 | 42AB61E320E4C56A007EEA69 /* MMDB.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42E68EC820D318C300E715DE /* MMDB.framework */; }; 32 | 42AB61E420E4C5A4007EEA69 /* CocoaLumberjackSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42AB61DB20E4A8AA007EEA69 /* CocoaLumberjackSwift.framework */; }; 33 | 42AB61E520E4C64B007EEA69 /* CocoaAsyncSocket.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42AB61D920E4A8A9007EEA69 /* CocoaAsyncSocket.framework */; }; 34 | 42AB61E620E4C64B007EEA69 /* CocoaLumberjack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42AB61DA20E4A8AA007EEA69 /* CocoaLumberjack.framework */; }; 35 | 42AB61E720E4C64B007EEA69 /* Resolver.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42E68EC520D318C200E715DE /* Resolver.framework */; }; 36 | 42AB61E820E4C64B007EEA69 /* Sodium.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42E68EC720D318C300E715DE /* Sodium.framework */; }; 37 | 42AB61E920E4C6E7007EEA69 /* lwip.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42E68EC920D318C300E715DE /* lwip.framework */; }; 38 | 42AB61EA20E4C6E7007EEA69 /* tun2socks.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42E68ECA20D318C300E715DE /* tun2socks.framework */; }; 39 | 42AB61EB20E4C6E7007EEA69 /* Yaml.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42E68EC620D318C200E715DE /* Yaml.framework */; }; 40 | 42C5E33520DE3C4F0011D42A /* RequestRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 421EB72D20D8D26F00B05640 /* RequestRecord.swift */; }; 41 | 42C5E33620DE3D410011D42A /* Realm.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 421EB72A20D8CF8B00B05640 /* Realm.framework */; }; 42 | 42C5E33820DE6D7E0011D42A /* RealmUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C5E33720DE6D7E0011D42A /* RealmUtil.swift */; }; 43 | 42C5E33920DE6E830011D42A /* RealmUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C5E33720DE6D7E0011D42A /* RealmUtil.swift */; }; 44 | 42C5E33A20DE71A00011D42A /* ProxyObserverFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42427FFB20D39AF30053FA82 /* ProxyObserverFactory.swift */; }; 45 | 42C5E33B20DE73490011D42A /* NEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42E68EC320D3177900E715DE /* NEKit.framework */; }; 46 | 42C891C520E0946100CB24A2 /* TableSegment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C891C420E0946100CB24A2 /* TableSegment.swift */; }; 47 | 42C891CF20E0ECF900CB24A2 /* SegmentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C891CE20E0ECF900CB24A2 /* SegmentController.swift */; }; 48 | 42DA4DAB20C8C86E002D161F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42DA4DAA20C8C86E002D161F /* AppDelegate.swift */; }; 49 | 42DA4DB220C8C86E002D161F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 42DA4DB020C8C86E002D161F /* Main.storyboard */; }; 50 | 42DA4DB420C8C86F002D161F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 42DA4DB320C8C86F002D161F /* Assets.xcassets */; }; 51 | 42DA4DB720C8C86F002D161F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 42DA4DB520C8C86F002D161F /* LaunchScreen.storyboard */; }; 52 | 42DA4DC220C8C86F002D161F /* ImageCrawlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42DA4DC120C8C86F002D161F /* ImageCrawlerTests.swift */; }; 53 | 42DA4DCD20C8C86F002D161F /* ImageCrawlerUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42DA4DCC20C8C86F002D161F /* ImageCrawlerUITests.swift */; }; 54 | 42DA4DDC20C8CA13002D161F /* Kingfisher.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42DA4DDB20C8CA13002D161F /* Kingfisher.framework */; }; 55 | 42EB235520CAB92F00994F74 /* Switch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42EB235420CAB92F00994F74 /* Switch.framework */; }; 56 | 42EEC93820DC7B040009A6AC /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42EEC93720DC7B040009A6AC /* NetworkManager.swift */; }; 57 | 42EEC94020DCCFFA0009A6AC /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42EEC93F20DCCFFA0009A6AC /* PacketTunnelProvider.swift */; }; 58 | 42EEC94520DCCFFA0009A6AC /* TunnelProvider.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 42EEC93D20DCCFFA0009A6AC /* TunnelProvider.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 59 | 42EEC95120DCF5310009A6AC /* CocoaAsyncSocket.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42EEC95020DCF5310009A6AC /* CocoaAsyncSocket.framework */; }; 60 | /* End PBXBuildFile section */ 61 | 62 | /* Begin PBXContainerItemProxy section */ 63 | 421EB70C20D8966700B05640 /* PBXContainerItemProxy */ = { 64 | isa = PBXContainerItemProxy; 65 | containerPortal = 421EB70420D8966700B05640 /* NEKit.xcodeproj */; 66 | proxyType = 2; 67 | remoteGlobalIDString = 36463A301CDCD5EB0040579C; 68 | remoteInfo = "NEKit-macOS"; 69 | }; 70 | 421EB70E20D8966700B05640 /* PBXContainerItemProxy */ = { 71 | isa = PBXContainerItemProxy; 72 | containerPortal = 421EB70420D8966700B05640 /* NEKit.xcodeproj */; 73 | proxyType = 2; 74 | remoteGlobalIDString = 36C48D4D1CF88DED0071804F; 75 | remoteInfo = "NEKit-iOS"; 76 | }; 77 | 421EB71020D8966700B05640 /* PBXContainerItemProxy */ = { 78 | isa = PBXContainerItemProxy; 79 | containerPortal = 421EB70420D8966700B05640 /* NEKit.xcodeproj */; 80 | proxyType = 2; 81 | remoteGlobalIDString = 36A719981D5EEB4900DC35F5; 82 | remoteInfo = NEKitDemo; 83 | }; 84 | 421EB71220D8966700B05640 /* PBXContainerItemProxy */ = { 85 | isa = PBXContainerItemProxy; 86 | containerPortal = 421EB70420D8966700B05640 /* NEKit.xcodeproj */; 87 | proxyType = 2; 88 | remoteGlobalIDString = 362347131D7D44E700A047DE; 89 | remoteInfo = "NEKitTest-macOS"; 90 | }; 91 | 421EB71420D8966700B05640 /* PBXContainerItemProxy */ = { 92 | isa = PBXContainerItemProxy; 93 | containerPortal = 421EB70420D8966700B05640 /* NEKit.xcodeproj */; 94 | proxyType = 2; 95 | remoteGlobalIDString = 362347221D7D458E00A047DE; 96 | remoteInfo = "NEKitTests-iOS"; 97 | }; 98 | 42C5E32F20DE3BAE0011D42A /* PBXContainerItemProxy */ = { 99 | isa = PBXContainerItemProxy; 100 | containerPortal = 42DA4D9F20C8C86E002D161F /* Project object */; 101 | proxyType = 1; 102 | remoteGlobalIDString = 42DA4DA620C8C86E002D161F; 103 | remoteInfo = ImageCrawler; 104 | }; 105 | 42DA4DBE20C8C86F002D161F /* PBXContainerItemProxy */ = { 106 | isa = PBXContainerItemProxy; 107 | containerPortal = 42DA4D9F20C8C86E002D161F /* Project object */; 108 | proxyType = 1; 109 | remoteGlobalIDString = 42DA4DA620C8C86E002D161F; 110 | remoteInfo = ImageCrawler; 111 | }; 112 | 42DA4DC920C8C86F002D161F /* PBXContainerItemProxy */ = { 113 | isa = PBXContainerItemProxy; 114 | containerPortal = 42DA4D9F20C8C86E002D161F /* Project object */; 115 | proxyType = 1; 116 | remoteGlobalIDString = 42DA4DA620C8C86E002D161F; 117 | remoteInfo = ImageCrawler; 118 | }; 119 | 42EEC94320DCCFFA0009A6AC /* PBXContainerItemProxy */ = { 120 | isa = PBXContainerItemProxy; 121 | containerPortal = 42DA4D9F20C8C86E002D161F /* Project object */; 122 | proxyType = 1; 123 | remoteGlobalIDString = 42EEC93C20DCCFFA0009A6AC; 124 | remoteInfo = CrawlerTunnelProvider; 125 | }; 126 | /* End PBXContainerItemProxy section */ 127 | 128 | /* Begin PBXCopyFilesBuildPhase section */ 129 | 4222EAD920CF9871000967CC /* Embed App Extensions */ = { 130 | isa = PBXCopyFilesBuildPhase; 131 | buildActionMask = 2147483647; 132 | dstPath = ""; 133 | dstSubfolderSpec = 13; 134 | files = ( 135 | 42EEC94520DCCFFA0009A6AC /* TunnelProvider.appex in Embed App Extensions */, 136 | ); 137 | name = "Embed App Extensions"; 138 | runOnlyForDeploymentPostprocessing = 0; 139 | }; 140 | /* End PBXCopyFilesBuildPhase section */ 141 | 142 | /* Begin PBXFileReference section */ 143 | 420446AE20DA3F6300ABDF31 /* RecordController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordController.swift; sourceTree = ""; }; 144 | 420446B020DA45A800ABDF31 /* RecordCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordCell.swift; sourceTree = ""; }; 145 | 421EB70420D8966700B05640 /* NEKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = NEKit.xcodeproj; path = ../NEKit/NEKit.xcodeproj; sourceTree = ""; }; 146 | 421EB72820D8CF5A00B05640 /* RealmSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RealmSwift.framework; path = Carthage/Build/iOS/RealmSwift.framework; sourceTree = ""; }; 147 | 421EB72A20D8CF8B00B05640 /* Realm.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Realm.framework; path = Carthage/Build/iOS/Realm.framework; sourceTree = ""; }; 148 | 421EB72D20D8D26F00B05640 /* RequestRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestRecord.swift; sourceTree = ""; }; 149 | 423838E120E63CC8008AE7A8 /* HarProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HarProvider.swift; sourceTree = ""; }; 150 | 423838E320E6FBCB008AE7A8 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/iOS/SwiftyJSON.framework; sourceTree = ""; }; 151 | 42427FFB20D39AF30053FA82 /* ProxyObserverFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyObserverFactory.swift; sourceTree = ""; }; 152 | 4256260A20DFAF320033E0A8 /* DebugUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugUtil.swift; sourceTree = ""; }; 153 | 428CF3BA20DB4CC6009D90A2 /* HomeController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeController.swift; sourceTree = ""; }; 154 | 428CF3C020DB90F8009D90A2 /* DetailController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailController.swift; sourceTree = ""; }; 155 | 428CF3C320DB97A1009D90A2 /* DetailContentCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailContentCell.swift; sourceTree = ""; }; 156 | 42A18C3A20E99E1E00DD4AA5 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; }; 157 | 42AB61AF20E0ED8F007EEA69 /* SummarySegmentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SummarySegmentController.swift; sourceTree = ""; }; 158 | 42AB61B520E10BF1007EEA69 /* SwiftDate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftDate.framework; path = Carthage/Build/iOS/SwiftDate.framework; sourceTree = ""; }; 159 | 42AB61B720E1161B007EEA69 /* RequestSegmentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestSegmentController.swift; sourceTree = ""; }; 160 | 42AB61BB20E2141A007EEA69 /* HttpBodyController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HttpBodyController.swift; sourceTree = ""; }; 161 | 42AB61BD20E218B9007EEA69 /* ResponseSegmentController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResponseSegmentController.swift; sourceTree = ""; }; 162 | 42AB61BF20E231F2007EEA69 /* Highlightr.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Highlightr.framework; path = Carthage/Build/iOS/Highlightr.framework; sourceTree = ""; }; 163 | 42AB61C120E2473B007EEA69 /* SwitcherController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwitcherController.swift; sourceTree = ""; }; 164 | 42AB61D920E4A8A9007EEA69 /* CocoaAsyncSocket.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CocoaAsyncSocket.framework; path = Carthage/Build/iOS/CocoaAsyncSocket.framework; sourceTree = ""; }; 165 | 42AB61DA20E4A8AA007EEA69 /* CocoaLumberjack.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CocoaLumberjack.framework; path = Carthage/Build/iOS/CocoaLumberjack.framework; sourceTree = ""; }; 166 | 42AB61DB20E4A8AA007EEA69 /* CocoaLumberjackSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CocoaLumberjackSwift.framework; path = Carthage/Build/iOS/CocoaLumberjackSwift.framework; sourceTree = ""; }; 167 | 42C5E33720DE6D7E0011D42A /* RealmUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealmUtil.swift; sourceTree = ""; }; 168 | 42C891C420E0946100CB24A2 /* TableSegment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableSegment.swift; sourceTree = ""; }; 169 | 42C891CE20E0ECF900CB24A2 /* SegmentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegmentController.swift; sourceTree = ""; }; 170 | 42DA4DA720C8C86E002D161F /* ImageCrawler.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ImageCrawler.app; sourceTree = BUILT_PRODUCTS_DIR; }; 171 | 42DA4DAA20C8C86E002D161F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 172 | 42DA4DB120C8C86E002D161F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 173 | 42DA4DB320C8C86F002D161F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 174 | 42DA4DB620C8C86F002D161F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 175 | 42DA4DB820C8C86F002D161F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 176 | 42DA4DBD20C8C86F002D161F /* ImageCrawlerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ImageCrawlerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 177 | 42DA4DC120C8C86F002D161F /* ImageCrawlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCrawlerTests.swift; sourceTree = ""; }; 178 | 42DA4DC320C8C86F002D161F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 179 | 42DA4DC820C8C86F002D161F /* ImageCrawlerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ImageCrawlerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 180 | 42DA4DCC20C8C86F002D161F /* ImageCrawlerUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCrawlerUITests.swift; sourceTree = ""; }; 181 | 42DA4DCE20C8C86F002D161F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 182 | 42DA4DDB20C8CA13002D161F /* Kingfisher.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Kingfisher.framework; path = Carthage/Build/iOS/Kingfisher.framework; sourceTree = ""; }; 183 | 42E68EC320D3177900E715DE /* NEKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NEKit.framework; path = Carthage/Build/iOS/NEKit.framework; sourceTree = ""; }; 184 | 42E68EC520D318C200E715DE /* Resolver.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Resolver.framework; path = Carthage/Build/iOS/Resolver.framework; sourceTree = ""; }; 185 | 42E68EC620D318C200E715DE /* Yaml.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Yaml.framework; path = Carthage/Build/iOS/Yaml.framework; sourceTree = ""; }; 186 | 42E68EC720D318C300E715DE /* Sodium.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sodium.framework; path = Carthage/Build/iOS/Sodium.framework; sourceTree = ""; }; 187 | 42E68EC820D318C300E715DE /* MMDB.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MMDB.framework; path = Carthage/Build/iOS/MMDB.framework; sourceTree = ""; }; 188 | 42E68EC920D318C300E715DE /* lwip.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = lwip.framework; path = Carthage/Build/iOS/lwip.framework; sourceTree = ""; }; 189 | 42E68ECA20D318C300E715DE /* tun2socks.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = tun2socks.framework; path = Carthage/Build/iOS/tun2socks.framework; sourceTree = ""; }; 190 | 42EB235320CA2F1F00994F74 /* ImageCrawler.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ImageCrawler.entitlements; sourceTree = ""; }; 191 | 42EB235420CAB92F00994F74 /* Switch.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Switch.framework; path = Carthage/Build/iOS/Switch.framework; sourceTree = ""; }; 192 | 42EEC93720DC7B040009A6AC /* NetworkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = ""; }; 193 | 42EEC93D20DCCFFA0009A6AC /* TunnelProvider.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = TunnelProvider.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 194 | 42EEC93F20DCCFFA0009A6AC /* PacketTunnelProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelProvider.swift; sourceTree = ""; }; 195 | 42EEC94120DCCFFA0009A6AC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 196 | 42EEC94220DCCFFA0009A6AC /* TunnelProvider.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TunnelProvider.entitlements; sourceTree = ""; }; 197 | 42EEC95020DCF5310009A6AC /* CocoaAsyncSocket.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CocoaAsyncSocket.framework; path = Carthage/Build/iOS/CocoaAsyncSocket.framework; sourceTree = ""; }; 198 | /* End PBXFileReference section */ 199 | 200 | /* Begin PBXFrameworksBuildPhase section */ 201 | 42DA4DA420C8C86E002D161F /* Frameworks */ = { 202 | isa = PBXFrameworksBuildPhase; 203 | buildActionMask = 2147483647; 204 | files = ( 205 | 423838E420E6FBCB008AE7A8 /* SwiftyJSON.framework in Frameworks */, 206 | 42AB61E220E4C3D9007EEA69 /* NEKit.framework in Frameworks */, 207 | 42AB61C020E231F2007EEA69 /* Highlightr.framework in Frameworks */, 208 | 42AB61B620E10BF1007EEA69 /* SwiftDate.framework in Frameworks */, 209 | 42EB235520CAB92F00994F74 /* Switch.framework in Frameworks */, 210 | 421EB72920D8CF5A00B05640 /* RealmSwift.framework in Frameworks */, 211 | 42DA4DDC20C8CA13002D161F /* Kingfisher.framework in Frameworks */, 212 | 42AB61E320E4C56A007EEA69 /* MMDB.framework in Frameworks */, 213 | 42AB61E420E4C5A4007EEA69 /* CocoaLumberjackSwift.framework in Frameworks */, 214 | 421EB72B20D8CF8B00B05640 /* Realm.framework in Frameworks */, 215 | 42AB61E520E4C64B007EEA69 /* CocoaAsyncSocket.framework in Frameworks */, 216 | 42AB61E620E4C64B007EEA69 /* CocoaLumberjack.framework in Frameworks */, 217 | 42AB61E920E4C6E7007EEA69 /* lwip.framework in Frameworks */, 218 | 42A18C3B20E99E1E00DD4AA5 /* NetworkExtension.framework in Frameworks */, 219 | 42AB61E720E4C64B007EEA69 /* Resolver.framework in Frameworks */, 220 | 42AB61EA20E4C6E7007EEA69 /* tun2socks.framework in Frameworks */, 221 | 42AB61EB20E4C6E7007EEA69 /* Yaml.framework in Frameworks */, 222 | 42AB61E820E4C64B007EEA69 /* Sodium.framework in Frameworks */, 223 | ); 224 | runOnlyForDeploymentPostprocessing = 0; 225 | }; 226 | 42DA4DBA20C8C86F002D161F /* Frameworks */ = { 227 | isa = PBXFrameworksBuildPhase; 228 | buildActionMask = 2147483647; 229 | files = ( 230 | ); 231 | runOnlyForDeploymentPostprocessing = 0; 232 | }; 233 | 42DA4DC520C8C86F002D161F /* Frameworks */ = { 234 | isa = PBXFrameworksBuildPhase; 235 | buildActionMask = 2147483647; 236 | files = ( 237 | ); 238 | runOnlyForDeploymentPostprocessing = 0; 239 | }; 240 | 42EEC93A20DCCFFA0009A6AC /* Frameworks */ = { 241 | isa = PBXFrameworksBuildPhase; 242 | buildActionMask = 2147483647; 243 | files = ( 244 | 42C5E33B20DE73490011D42A /* NEKit.framework in Frameworks */, 245 | 42A18C3C20E99ED400DD4AA5 /* NetworkExtension.framework in Frameworks */, 246 | 42EEC95120DCF5310009A6AC /* CocoaAsyncSocket.framework in Frameworks */, 247 | 42C5E33620DE3D410011D42A /* Realm.framework in Frameworks */, 248 | ); 249 | runOnlyForDeploymentPostprocessing = 0; 250 | }; 251 | /* End PBXFrameworksBuildPhase section */ 252 | 253 | /* Begin PBXGroup section */ 254 | 421EB70520D8966700B05640 /* Products */ = { 255 | isa = PBXGroup; 256 | children = ( 257 | 421EB70D20D8966700B05640 /* NEKit.framework */, 258 | 421EB70F20D8966700B05640 /* NEKit.framework */, 259 | 421EB71120D8966700B05640 /* NEKitDemo.app */, 260 | 421EB71320D8966700B05640 /* NEKitTest-macOS.xctest */, 261 | 421EB71520D8966700B05640 /* NEKitTests-iOS.xctest */, 262 | ); 263 | name = Products; 264 | sourceTree = ""; 265 | }; 266 | 421EB72C20D8D24F00B05640 /* Models */ = { 267 | isa = PBXGroup; 268 | children = ( 269 | 421EB72D20D8D26F00B05640 /* RequestRecord.swift */, 270 | ); 271 | path = Models; 272 | sourceTree = ""; 273 | }; 274 | 428CF3C220DB9780009D90A2 /* Views */ = { 275 | isa = PBXGroup; 276 | children = ( 277 | 420446B020DA45A800ABDF31 /* RecordCell.swift */, 278 | 428CF3C320DB97A1009D90A2 /* DetailContentCell.swift */, 279 | ); 280 | path = Views; 281 | sourceTree = ""; 282 | }; 283 | 42C891CA20E0E2B600CB24A2 /* ViewControllers */ = { 284 | isa = PBXGroup; 285 | children = ( 286 | 420446AE20DA3F6300ABDF31 /* RecordController.swift */, 287 | 428CF3BA20DB4CC6009D90A2 /* HomeController.swift */, 288 | 428CF3C020DB90F8009D90A2 /* DetailController.swift */, 289 | 42C891CE20E0ECF900CB24A2 /* SegmentController.swift */, 290 | 42AB61AF20E0ED8F007EEA69 /* SummarySegmentController.swift */, 291 | 42AB61BB20E2141A007EEA69 /* HttpBodyController.swift */, 292 | 42AB61B720E1161B007EEA69 /* RequestSegmentController.swift */, 293 | 42AB61BD20E218B9007EEA69 /* ResponseSegmentController.swift */, 294 | 42AB61C120E2473B007EEA69 /* SwitcherController.swift */, 295 | ); 296 | path = ViewControllers; 297 | sourceTree = ""; 298 | }; 299 | 42DA4D9E20C8C86E002D161F = { 300 | isa = PBXGroup; 301 | children = ( 302 | 42AB61D920E4A8A9007EEA69 /* CocoaAsyncSocket.framework */, 303 | 42AB61DA20E4A8AA007EEA69 /* CocoaLumberjack.framework */, 304 | 42AB61DB20E4A8AA007EEA69 /* CocoaLumberjackSwift.framework */, 305 | 42DA4DA920C8C86E002D161F /* ImageCrawler */, 306 | 42DA4DC020C8C86F002D161F /* ImageCrawlerTests */, 307 | 42DA4DCB20C8C86F002D161F /* ImageCrawlerUITests */, 308 | 42EEC93E20DCCFFA0009A6AC /* TunnelProvider */, 309 | 42DA4DA820C8C86E002D161F /* Products */, 310 | 42DA4DDA20C8CA13002D161F /* Frameworks */, 311 | ); 312 | sourceTree = ""; 313 | }; 314 | 42DA4DA820C8C86E002D161F /* Products */ = { 315 | isa = PBXGroup; 316 | children = ( 317 | 42DA4DA720C8C86E002D161F /* ImageCrawler.app */, 318 | 42DA4DBD20C8C86F002D161F /* ImageCrawlerTests.xctest */, 319 | 42DA4DC820C8C86F002D161F /* ImageCrawlerUITests.xctest */, 320 | 42EEC93D20DCCFFA0009A6AC /* TunnelProvider.appex */, 321 | ); 322 | name = Products; 323 | sourceTree = ""; 324 | }; 325 | 42DA4DA920C8C86E002D161F /* ImageCrawler */ = { 326 | isa = PBXGroup; 327 | children = ( 328 | 42C891CA20E0E2B600CB24A2 /* ViewControllers */, 329 | 42EEC93620DC7AEF0009A6AC /* Utils */, 330 | 428CF3C220DB9780009D90A2 /* Views */, 331 | 421EB72C20D8D24F00B05640 /* Models */, 332 | 42EB235320CA2F1F00994F74 /* ImageCrawler.entitlements */, 333 | 42DA4DAA20C8C86E002D161F /* AppDelegate.swift */, 334 | 42DA4DB020C8C86E002D161F /* Main.storyboard */, 335 | 42DA4DB320C8C86F002D161F /* Assets.xcassets */, 336 | 42DA4DB520C8C86F002D161F /* LaunchScreen.storyboard */, 337 | 42DA4DB820C8C86F002D161F /* Info.plist */, 338 | ); 339 | path = ImageCrawler; 340 | sourceTree = ""; 341 | }; 342 | 42DA4DC020C8C86F002D161F /* ImageCrawlerTests */ = { 343 | isa = PBXGroup; 344 | children = ( 345 | 42DA4DC120C8C86F002D161F /* ImageCrawlerTests.swift */, 346 | 42DA4DC320C8C86F002D161F /* Info.plist */, 347 | ); 348 | path = ImageCrawlerTests; 349 | sourceTree = ""; 350 | }; 351 | 42DA4DCB20C8C86F002D161F /* ImageCrawlerUITests */ = { 352 | isa = PBXGroup; 353 | children = ( 354 | 42DA4DCC20C8C86F002D161F /* ImageCrawlerUITests.swift */, 355 | 42DA4DCE20C8C86F002D161F /* Info.plist */, 356 | ); 357 | path = ImageCrawlerUITests; 358 | sourceTree = ""; 359 | }; 360 | 42DA4DDA20C8CA13002D161F /* Frameworks */ = { 361 | isa = PBXGroup; 362 | children = ( 363 | 42A18C3A20E99E1E00DD4AA5 /* NetworkExtension.framework */, 364 | 423838E320E6FBCB008AE7A8 /* SwiftyJSON.framework */, 365 | 42AB61BF20E231F2007EEA69 /* Highlightr.framework */, 366 | 42AB61B520E10BF1007EEA69 /* SwiftDate.framework */, 367 | 42EEC95020DCF5310009A6AC /* CocoaAsyncSocket.framework */, 368 | 421EB72A20D8CF8B00B05640 /* Realm.framework */, 369 | 421EB72820D8CF5A00B05640 /* RealmSwift.framework */, 370 | 421EB70420D8966700B05640 /* NEKit.xcodeproj */, 371 | 42E68EC920D318C300E715DE /* lwip.framework */, 372 | 42E68EC820D318C300E715DE /* MMDB.framework */, 373 | 42E68EC520D318C200E715DE /* Resolver.framework */, 374 | 42E68EC720D318C300E715DE /* Sodium.framework */, 375 | 42E68ECA20D318C300E715DE /* tun2socks.framework */, 376 | 42E68EC620D318C200E715DE /* Yaml.framework */, 377 | 42E68EC320D3177900E715DE /* NEKit.framework */, 378 | 42EB235420CAB92F00994F74 /* Switch.framework */, 379 | 42DA4DDB20C8CA13002D161F /* Kingfisher.framework */, 380 | ); 381 | name = Frameworks; 382 | sourceTree = ""; 383 | }; 384 | 42EEC93620DC7AEF0009A6AC /* Utils */ = { 385 | isa = PBXGroup; 386 | children = ( 387 | 42EEC93720DC7B040009A6AC /* NetworkManager.swift */, 388 | 42C5E33720DE6D7E0011D42A /* RealmUtil.swift */, 389 | 4256260A20DFAF320033E0A8 /* DebugUtil.swift */, 390 | 42C891C420E0946100CB24A2 /* TableSegment.swift */, 391 | 423838E120E63CC8008AE7A8 /* HarProvider.swift */, 392 | ); 393 | path = Utils; 394 | sourceTree = ""; 395 | }; 396 | 42EEC93E20DCCFFA0009A6AC /* TunnelProvider */ = { 397 | isa = PBXGroup; 398 | children = ( 399 | 42427FFB20D39AF30053FA82 /* ProxyObserverFactory.swift */, 400 | 42EEC93F20DCCFFA0009A6AC /* PacketTunnelProvider.swift */, 401 | 42EEC94120DCCFFA0009A6AC /* Info.plist */, 402 | 42EEC94220DCCFFA0009A6AC /* TunnelProvider.entitlements */, 403 | ); 404 | path = TunnelProvider; 405 | sourceTree = ""; 406 | }; 407 | /* End PBXGroup section */ 408 | 409 | /* Begin PBXNativeTarget section */ 410 | 42DA4DA620C8C86E002D161F /* ImageCrawler */ = { 411 | isa = PBXNativeTarget; 412 | buildConfigurationList = 42DA4DD120C8C86F002D161F /* Build configuration list for PBXNativeTarget "ImageCrawler" */; 413 | buildPhases = ( 414 | 42DA4DA320C8C86E002D161F /* Sources */, 415 | 42DA4DA420C8C86E002D161F /* Frameworks */, 416 | 42DA4DA520C8C86E002D161F /* Resources */, 417 | 42DA4DDD20C8CA3E002D161F /* Run Script */, 418 | 4222EAD920CF9871000967CC /* Embed App Extensions */, 419 | ); 420 | buildRules = ( 421 | ); 422 | dependencies = ( 423 | 42EEC94420DCCFFA0009A6AC /* PBXTargetDependency */, 424 | ); 425 | name = ImageCrawler; 426 | productName = ImageCrawler; 427 | productReference = 42DA4DA720C8C86E002D161F /* ImageCrawler.app */; 428 | productType = "com.apple.product-type.application"; 429 | }; 430 | 42DA4DBC20C8C86F002D161F /* ImageCrawlerTests */ = { 431 | isa = PBXNativeTarget; 432 | buildConfigurationList = 42DA4DD420C8C86F002D161F /* Build configuration list for PBXNativeTarget "ImageCrawlerTests" */; 433 | buildPhases = ( 434 | 42DA4DB920C8C86F002D161F /* Sources */, 435 | 42DA4DBA20C8C86F002D161F /* Frameworks */, 436 | 42DA4DBB20C8C86F002D161F /* Resources */, 437 | ); 438 | buildRules = ( 439 | ); 440 | dependencies = ( 441 | 42DA4DBF20C8C86F002D161F /* PBXTargetDependency */, 442 | ); 443 | name = ImageCrawlerTests; 444 | productName = ImageCrawlerTests; 445 | productReference = 42DA4DBD20C8C86F002D161F /* ImageCrawlerTests.xctest */; 446 | productType = "com.apple.product-type.bundle.unit-test"; 447 | }; 448 | 42DA4DC720C8C86F002D161F /* ImageCrawlerUITests */ = { 449 | isa = PBXNativeTarget; 450 | buildConfigurationList = 42DA4DD720C8C86F002D161F /* Build configuration list for PBXNativeTarget "ImageCrawlerUITests" */; 451 | buildPhases = ( 452 | 42DA4DC420C8C86F002D161F /* Sources */, 453 | 42DA4DC520C8C86F002D161F /* Frameworks */, 454 | 42DA4DC620C8C86F002D161F /* Resources */, 455 | ); 456 | buildRules = ( 457 | ); 458 | dependencies = ( 459 | 42DA4DCA20C8C86F002D161F /* PBXTargetDependency */, 460 | ); 461 | name = ImageCrawlerUITests; 462 | productName = ImageCrawlerUITests; 463 | productReference = 42DA4DC820C8C86F002D161F /* ImageCrawlerUITests.xctest */; 464 | productType = "com.apple.product-type.bundle.ui-testing"; 465 | }; 466 | 42EEC93C20DCCFFA0009A6AC /* TunnelProvider */ = { 467 | isa = PBXNativeTarget; 468 | buildConfigurationList = 42EEC94620DCCFFA0009A6AC /* Build configuration list for PBXNativeTarget "TunnelProvider" */; 469 | buildPhases = ( 470 | 42EEC93920DCCFFA0009A6AC /* Sources */, 471 | 42EEC93A20DCCFFA0009A6AC /* Frameworks */, 472 | 42EEC93B20DCCFFA0009A6AC /* Resources */, 473 | ); 474 | buildRules = ( 475 | ); 476 | dependencies = ( 477 | 42C5E33020DE3BAE0011D42A /* PBXTargetDependency */, 478 | ); 479 | name = TunnelProvider; 480 | productName = CrawlerTunnelProvider; 481 | productReference = 42EEC93D20DCCFFA0009A6AC /* TunnelProvider.appex */; 482 | productType = "com.apple.product-type.app-extension"; 483 | }; 484 | /* End PBXNativeTarget section */ 485 | 486 | /* Begin PBXProject section */ 487 | 42DA4D9F20C8C86E002D161F /* Project object */ = { 488 | isa = PBXProject; 489 | attributes = { 490 | LastSwiftUpdateCheck = 0940; 491 | LastUpgradeCheck = 0940; 492 | ORGANIZATIONNAME = "Frank Cheng"; 493 | TargetAttributes = { 494 | 42DA4DA620C8C86E002D161F = { 495 | CreatedOnToolsVersion = 9.4; 496 | SystemCapabilities = { 497 | com.apple.ApplicationGroups.iOS = { 498 | enabled = 1; 499 | }; 500 | com.apple.InAppPurchase = { 501 | enabled = 0; 502 | }; 503 | com.apple.Keychain = { 504 | enabled = 1; 505 | }; 506 | com.apple.NetworkExtensions.iOS = { 507 | enabled = 1; 508 | }; 509 | com.apple.VPNLite = { 510 | enabled = 0; 511 | }; 512 | }; 513 | }; 514 | 42DA4DBC20C8C86F002D161F = { 515 | CreatedOnToolsVersion = 9.4; 516 | TestTargetID = 42DA4DA620C8C86E002D161F; 517 | }; 518 | 42DA4DC720C8C86F002D161F = { 519 | CreatedOnToolsVersion = 9.4; 520 | TestTargetID = 42DA4DA620C8C86E002D161F; 521 | }; 522 | 42EEC93C20DCCFFA0009A6AC = { 523 | CreatedOnToolsVersion = 9.4.1; 524 | SystemCapabilities = { 525 | com.apple.ApplicationGroups.iOS = { 526 | enabled = 1; 527 | }; 528 | com.apple.NetworkExtensions.iOS = { 529 | enabled = 1; 530 | }; 531 | com.apple.VPNLite = { 532 | enabled = 0; 533 | }; 534 | }; 535 | }; 536 | }; 537 | }; 538 | buildConfigurationList = 42DA4DA220C8C86E002D161F /* Build configuration list for PBXProject "ImageCrawler" */; 539 | compatibilityVersion = "Xcode 9.3"; 540 | developmentRegion = en; 541 | hasScannedForEncodings = 0; 542 | knownRegions = ( 543 | en, 544 | Base, 545 | ); 546 | mainGroup = 42DA4D9E20C8C86E002D161F; 547 | productRefGroup = 42DA4DA820C8C86E002D161F /* Products */; 548 | projectDirPath = ""; 549 | projectReferences = ( 550 | { 551 | ProductGroup = 421EB70520D8966700B05640 /* Products */; 552 | ProjectRef = 421EB70420D8966700B05640 /* NEKit.xcodeproj */; 553 | }, 554 | ); 555 | projectRoot = ""; 556 | targets = ( 557 | 42DA4DA620C8C86E002D161F /* ImageCrawler */, 558 | 42DA4DBC20C8C86F002D161F /* ImageCrawlerTests */, 559 | 42DA4DC720C8C86F002D161F /* ImageCrawlerUITests */, 560 | 42EEC93C20DCCFFA0009A6AC /* TunnelProvider */, 561 | ); 562 | }; 563 | /* End PBXProject section */ 564 | 565 | /* Begin PBXReferenceProxy section */ 566 | 421EB70D20D8966700B05640 /* NEKit.framework */ = { 567 | isa = PBXReferenceProxy; 568 | fileType = wrapper.framework; 569 | path = NEKit.framework; 570 | remoteRef = 421EB70C20D8966700B05640 /* PBXContainerItemProxy */; 571 | sourceTree = BUILT_PRODUCTS_DIR; 572 | }; 573 | 421EB70F20D8966700B05640 /* NEKit.framework */ = { 574 | isa = PBXReferenceProxy; 575 | fileType = wrapper.framework; 576 | path = NEKit.framework; 577 | remoteRef = 421EB70E20D8966700B05640 /* PBXContainerItemProxy */; 578 | sourceTree = BUILT_PRODUCTS_DIR; 579 | }; 580 | 421EB71120D8966700B05640 /* NEKitDemo.app */ = { 581 | isa = PBXReferenceProxy; 582 | fileType = wrapper.application; 583 | path = NEKitDemo.app; 584 | remoteRef = 421EB71020D8966700B05640 /* PBXContainerItemProxy */; 585 | sourceTree = BUILT_PRODUCTS_DIR; 586 | }; 587 | 421EB71320D8966700B05640 /* NEKitTest-macOS.xctest */ = { 588 | isa = PBXReferenceProxy; 589 | fileType = wrapper.cfbundle; 590 | path = "NEKitTest-macOS.xctest"; 591 | remoteRef = 421EB71220D8966700B05640 /* PBXContainerItemProxy */; 592 | sourceTree = BUILT_PRODUCTS_DIR; 593 | }; 594 | 421EB71520D8966700B05640 /* NEKitTests-iOS.xctest */ = { 595 | isa = PBXReferenceProxy; 596 | fileType = wrapper.cfbundle; 597 | path = "NEKitTests-iOS.xctest"; 598 | remoteRef = 421EB71420D8966700B05640 /* PBXContainerItemProxy */; 599 | sourceTree = BUILT_PRODUCTS_DIR; 600 | }; 601 | /* End PBXReferenceProxy section */ 602 | 603 | /* Begin PBXResourcesBuildPhase section */ 604 | 42DA4DA520C8C86E002D161F /* Resources */ = { 605 | isa = PBXResourcesBuildPhase; 606 | buildActionMask = 2147483647; 607 | files = ( 608 | 42DA4DB720C8C86F002D161F /* LaunchScreen.storyboard in Resources */, 609 | 42DA4DB420C8C86F002D161F /* Assets.xcassets in Resources */, 610 | 42DA4DB220C8C86E002D161F /* Main.storyboard in Resources */, 611 | ); 612 | runOnlyForDeploymentPostprocessing = 0; 613 | }; 614 | 42DA4DBB20C8C86F002D161F /* Resources */ = { 615 | isa = PBXResourcesBuildPhase; 616 | buildActionMask = 2147483647; 617 | files = ( 618 | ); 619 | runOnlyForDeploymentPostprocessing = 0; 620 | }; 621 | 42DA4DC620C8C86F002D161F /* Resources */ = { 622 | isa = PBXResourcesBuildPhase; 623 | buildActionMask = 2147483647; 624 | files = ( 625 | ); 626 | runOnlyForDeploymentPostprocessing = 0; 627 | }; 628 | 42EEC93B20DCCFFA0009A6AC /* Resources */ = { 629 | isa = PBXResourcesBuildPhase; 630 | buildActionMask = 2147483647; 631 | files = ( 632 | ); 633 | runOnlyForDeploymentPostprocessing = 0; 634 | }; 635 | /* End PBXResourcesBuildPhase section */ 636 | 637 | /* Begin PBXShellScriptBuildPhase section */ 638 | 42DA4DDD20C8CA3E002D161F /* Run Script */ = { 639 | isa = PBXShellScriptBuildPhase; 640 | buildActionMask = 2147483647; 641 | files = ( 642 | ); 643 | inputPaths = ( 644 | "$(SRCROOT)/Carthage/Build/iOS/Kingfisher.framework", 645 | "$(SRCROOT)/Carthage/Build/iOS/Switch.framework", 646 | "$(SRCROOT)/Carthage/Build/iOS/RealmSwift.framework", 647 | "$(SRCROOT)/Carthage/Build/iOS/Realm.framework", 648 | "$(SRCROOT)/Carthage/Build/iOS/SwiftDate.framework", 649 | "$(SRCROOT)/Carthage/Build/iOS/Highlightr.framework", 650 | "$(SRCROOT)/Carthage/Build/iOS/NEKit.framework", 651 | "$(SRCROOT)/Carthage/Build/iOS/MMDB.framework", 652 | "$(SRCROOT)/Carthage/Build/iOS/CocoaLumberjackSwift.framework", 653 | "$(SRCROOT)/Carthage/Build/iOS/CocoaLumberjack.framework", 654 | "$(SRCROOT)/Carthage/Build/iOS/CocoaAsyncSocket.framework", 655 | "$(SRCROOT)/Carthage/Build/iOS/Resolver.framework", 656 | "$(SRCROOT)/Carthage/Build/iOS/lwip.framework", 657 | "$(SRCROOT)/Carthage/Build/iOS/tun2socks.framework", 658 | "$(SRCROOT)/Carthage/Build/iOS/Yaml.framework", 659 | "$(SRCROOT)/Carthage/Build/iOS/Sodium.framework", 660 | "$(SRCROOT)/Carthage/Build/iOS/SwiftyJSON.framework", 661 | ); 662 | name = "Run Script"; 663 | outputPaths = ( 664 | "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Kingfisher.framework", 665 | "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Switch.framework", 666 | "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/RealmSwift.framework", 667 | "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Realm.framework", 668 | "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/SwiftDate.framework", 669 | "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Highlightr.framework", 670 | "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/NEKit.framework", 671 | "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/MMDB.framework", 672 | "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/CocoaLumberjackSwift.framework", 673 | "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/CocoaLumberjack.framework", 674 | "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/CocoaAsyncSocket.framework", 675 | "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Resolver.framework", 676 | "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/lwip.framework", 677 | "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/tun2socks.framework", 678 | "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Yaml.framework", 679 | "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Sodium.framework", 680 | "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/SwiftyJSON.framework", 681 | ); 682 | runOnlyForDeploymentPostprocessing = 0; 683 | shellPath = /bin/sh; 684 | shellScript = "/usr/local/bin/carthage copy-frameworks"; 685 | }; 686 | /* End PBXShellScriptBuildPhase section */ 687 | 688 | /* Begin PBXSourcesBuildPhase section */ 689 | 42DA4DA320C8C86E002D161F /* Sources */ = { 690 | isa = PBXSourcesBuildPhase; 691 | buildActionMask = 2147483647; 692 | files = ( 693 | 42AB61BE20E218B9007EEA69 /* ResponseSegmentController.swift in Sources */, 694 | 428CF3C120DB90F8009D90A2 /* DetailController.swift in Sources */, 695 | 42EEC93820DC7B040009A6AC /* NetworkManager.swift in Sources */, 696 | 4256260B20DFAF320033E0A8 /* DebugUtil.swift in Sources */, 697 | 42AB61B820E1161B007EEA69 /* RequestSegmentController.swift in Sources */, 698 | 428CF3C420DB97A1009D90A2 /* DetailContentCell.swift in Sources */, 699 | 423838E220E63CC8008AE7A8 /* HarProvider.swift in Sources */, 700 | 420446AF20DA3F6300ABDF31 /* RecordController.swift in Sources */, 701 | 42C891CF20E0ECF900CB24A2 /* SegmentController.swift in Sources */, 702 | 428CF3BB20DB4CC6009D90A2 /* HomeController.swift in Sources */, 703 | 42C5E33820DE6D7E0011D42A /* RealmUtil.swift in Sources */, 704 | 42C891C520E0946100CB24A2 /* TableSegment.swift in Sources */, 705 | 42DA4DAB20C8C86E002D161F /* AppDelegate.swift in Sources */, 706 | 420446B120DA45A800ABDF31 /* RecordCell.swift in Sources */, 707 | 42AB61C220E2473B007EEA69 /* SwitcherController.swift in Sources */, 708 | 42AB61B020E0ED8F007EEA69 /* SummarySegmentController.swift in Sources */, 709 | 42AB61BC20E2141A007EEA69 /* HttpBodyController.swift in Sources */, 710 | 421EB72E20D8D26F00B05640 /* RequestRecord.swift in Sources */, 711 | ); 712 | runOnlyForDeploymentPostprocessing = 0; 713 | }; 714 | 42DA4DB920C8C86F002D161F /* Sources */ = { 715 | isa = PBXSourcesBuildPhase; 716 | buildActionMask = 2147483647; 717 | files = ( 718 | 42DA4DC220C8C86F002D161F /* ImageCrawlerTests.swift in Sources */, 719 | ); 720 | runOnlyForDeploymentPostprocessing = 0; 721 | }; 722 | 42DA4DC420C8C86F002D161F /* Sources */ = { 723 | isa = PBXSourcesBuildPhase; 724 | buildActionMask = 2147483647; 725 | files = ( 726 | 42DA4DCD20C8C86F002D161F /* ImageCrawlerUITests.swift in Sources */, 727 | ); 728 | runOnlyForDeploymentPostprocessing = 0; 729 | }; 730 | 42EEC93920DCCFFA0009A6AC /* Sources */ = { 731 | isa = PBXSourcesBuildPhase; 732 | buildActionMask = 2147483647; 733 | files = ( 734 | 42C5E33920DE6E830011D42A /* RealmUtil.swift in Sources */, 735 | 42C5E33520DE3C4F0011D42A /* RequestRecord.swift in Sources */, 736 | 42C5E33A20DE71A00011D42A /* ProxyObserverFactory.swift in Sources */, 737 | 42EEC94020DCCFFA0009A6AC /* PacketTunnelProvider.swift in Sources */, 738 | ); 739 | runOnlyForDeploymentPostprocessing = 0; 740 | }; 741 | /* End PBXSourcesBuildPhase section */ 742 | 743 | /* Begin PBXTargetDependency section */ 744 | 42C5E33020DE3BAE0011D42A /* PBXTargetDependency */ = { 745 | isa = PBXTargetDependency; 746 | target = 42DA4DA620C8C86E002D161F /* ImageCrawler */; 747 | targetProxy = 42C5E32F20DE3BAE0011D42A /* PBXContainerItemProxy */; 748 | }; 749 | 42DA4DBF20C8C86F002D161F /* PBXTargetDependency */ = { 750 | isa = PBXTargetDependency; 751 | target = 42DA4DA620C8C86E002D161F /* ImageCrawler */; 752 | targetProxy = 42DA4DBE20C8C86F002D161F /* PBXContainerItemProxy */; 753 | }; 754 | 42DA4DCA20C8C86F002D161F /* PBXTargetDependency */ = { 755 | isa = PBXTargetDependency; 756 | target = 42DA4DA620C8C86E002D161F /* ImageCrawler */; 757 | targetProxy = 42DA4DC920C8C86F002D161F /* PBXContainerItemProxy */; 758 | }; 759 | 42EEC94420DCCFFA0009A6AC /* PBXTargetDependency */ = { 760 | isa = PBXTargetDependency; 761 | target = 42EEC93C20DCCFFA0009A6AC /* TunnelProvider */; 762 | targetProxy = 42EEC94320DCCFFA0009A6AC /* PBXContainerItemProxy */; 763 | }; 764 | /* End PBXTargetDependency section */ 765 | 766 | /* Begin PBXVariantGroup section */ 767 | 42DA4DB020C8C86E002D161F /* Main.storyboard */ = { 768 | isa = PBXVariantGroup; 769 | children = ( 770 | 42DA4DB120C8C86E002D161F /* Base */, 771 | ); 772 | name = Main.storyboard; 773 | sourceTree = ""; 774 | }; 775 | 42DA4DB520C8C86F002D161F /* LaunchScreen.storyboard */ = { 776 | isa = PBXVariantGroup; 777 | children = ( 778 | 42DA4DB620C8C86F002D161F /* Base */, 779 | ); 780 | name = LaunchScreen.storyboard; 781 | sourceTree = ""; 782 | }; 783 | /* End PBXVariantGroup section */ 784 | 785 | /* Begin XCBuildConfiguration section */ 786 | 42DA4DCF20C8C86F002D161F /* Debug */ = { 787 | isa = XCBuildConfiguration; 788 | buildSettings = { 789 | ALWAYS_SEARCH_USER_PATHS = NO; 790 | CLANG_ANALYZER_NONNULL = YES; 791 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 792 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 793 | CLANG_CXX_LIBRARY = "libc++"; 794 | CLANG_ENABLE_MODULES = YES; 795 | CLANG_ENABLE_OBJC_ARC = YES; 796 | CLANG_ENABLE_OBJC_WEAK = YES; 797 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 798 | CLANG_WARN_BOOL_CONVERSION = YES; 799 | CLANG_WARN_COMMA = YES; 800 | CLANG_WARN_CONSTANT_CONVERSION = YES; 801 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 802 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 803 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 804 | CLANG_WARN_EMPTY_BODY = YES; 805 | CLANG_WARN_ENUM_CONVERSION = YES; 806 | CLANG_WARN_INFINITE_RECURSION = YES; 807 | CLANG_WARN_INT_CONVERSION = YES; 808 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 809 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 810 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 811 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 812 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 813 | CLANG_WARN_STRICT_PROTOTYPES = YES; 814 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 815 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 816 | CLANG_WARN_UNREACHABLE_CODE = YES; 817 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 818 | CODE_SIGN_IDENTITY = "iPhone Developer"; 819 | COPY_PHASE_STRIP = NO; 820 | DEBUG_INFORMATION_FORMAT = dwarf; 821 | ENABLE_STRICT_OBJC_MSGSEND = YES; 822 | ENABLE_TESTABILITY = YES; 823 | GCC_C_LANGUAGE_STANDARD = gnu11; 824 | GCC_DYNAMIC_NO_PIC = NO; 825 | GCC_NO_COMMON_BLOCKS = YES; 826 | GCC_OPTIMIZATION_LEVEL = 0; 827 | GCC_PREPROCESSOR_DEFINITIONS = ( 828 | "DEBUG=1", 829 | "$(inherited)", 830 | ); 831 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 832 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 833 | GCC_WARN_UNDECLARED_SELECTOR = YES; 834 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 835 | GCC_WARN_UNUSED_FUNCTION = YES; 836 | GCC_WARN_UNUSED_VARIABLE = YES; 837 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 838 | MTL_ENABLE_DEBUG_INFO = YES; 839 | ONLY_ACTIVE_ARCH = YES; 840 | SDKROOT = iphoneos; 841 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 842 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 843 | }; 844 | name = Debug; 845 | }; 846 | 42DA4DD020C8C86F002D161F /* Release */ = { 847 | isa = XCBuildConfiguration; 848 | buildSettings = { 849 | ALWAYS_SEARCH_USER_PATHS = NO; 850 | CLANG_ANALYZER_NONNULL = YES; 851 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 852 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 853 | CLANG_CXX_LIBRARY = "libc++"; 854 | CLANG_ENABLE_MODULES = YES; 855 | CLANG_ENABLE_OBJC_ARC = YES; 856 | CLANG_ENABLE_OBJC_WEAK = YES; 857 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 858 | CLANG_WARN_BOOL_CONVERSION = YES; 859 | CLANG_WARN_COMMA = YES; 860 | CLANG_WARN_CONSTANT_CONVERSION = YES; 861 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 862 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 863 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 864 | CLANG_WARN_EMPTY_BODY = YES; 865 | CLANG_WARN_ENUM_CONVERSION = YES; 866 | CLANG_WARN_INFINITE_RECURSION = YES; 867 | CLANG_WARN_INT_CONVERSION = YES; 868 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 869 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 870 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 871 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 872 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 873 | CLANG_WARN_STRICT_PROTOTYPES = YES; 874 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 875 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 876 | CLANG_WARN_UNREACHABLE_CODE = YES; 877 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 878 | CODE_SIGN_IDENTITY = "iPhone Developer"; 879 | COPY_PHASE_STRIP = NO; 880 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 881 | ENABLE_NS_ASSERTIONS = NO; 882 | ENABLE_STRICT_OBJC_MSGSEND = YES; 883 | GCC_C_LANGUAGE_STANDARD = gnu11; 884 | GCC_NO_COMMON_BLOCKS = YES; 885 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 886 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 887 | GCC_WARN_UNDECLARED_SELECTOR = YES; 888 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 889 | GCC_WARN_UNUSED_FUNCTION = YES; 890 | GCC_WARN_UNUSED_VARIABLE = YES; 891 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 892 | MTL_ENABLE_DEBUG_INFO = NO; 893 | SDKROOT = iphoneos; 894 | SWIFT_COMPILATION_MODE = wholemodule; 895 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 896 | VALIDATE_PRODUCT = YES; 897 | }; 898 | name = Release; 899 | }; 900 | 42DA4DD220C8C86F002D161F /* Debug */ = { 901 | isa = XCBuildConfiguration; 902 | buildSettings = { 903 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 904 | ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-1"; 905 | CODE_SIGN_ENTITLEMENTS = ImageCrawler/ImageCrawler.entitlements; 906 | CODE_SIGN_STYLE = Automatic; 907 | DEVELOPMENT_TEAM = S833P2K5YV; 908 | FRAMEWORK_SEARCH_PATHS = ( 909 | "$(inherited)", 910 | "$(PROJECT_DIR)/Carthage/Build/iOS", 911 | "$(PROJECT_DIR)", 912 | ); 913 | INFOPLIST_FILE = ImageCrawler/Info.plist; 914 | LD_RUNPATH_SEARCH_PATHS = ( 915 | "$(inherited)", 916 | "@executable_path/Frameworks", 917 | ); 918 | PRODUCT_BUNDLE_IDENTIFIER = com.bettycc.retry; 919 | PRODUCT_NAME = "$(TARGET_NAME)"; 920 | SWIFT_VERSION = 4.0; 921 | TARGETED_DEVICE_FAMILY = "1,2"; 922 | }; 923 | name = Debug; 924 | }; 925 | 42DA4DD320C8C86F002D161F /* Release */ = { 926 | isa = XCBuildConfiguration; 927 | buildSettings = { 928 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 929 | ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-1"; 930 | CODE_SIGN_ENTITLEMENTS = ImageCrawler/ImageCrawler.entitlements; 931 | CODE_SIGN_STYLE = Automatic; 932 | DEVELOPMENT_TEAM = S833P2K5YV; 933 | FRAMEWORK_SEARCH_PATHS = ( 934 | "$(inherited)", 935 | "$(PROJECT_DIR)/Carthage/Build/iOS", 936 | "$(PROJECT_DIR)", 937 | ); 938 | INFOPLIST_FILE = ImageCrawler/Info.plist; 939 | LD_RUNPATH_SEARCH_PATHS = ( 940 | "$(inherited)", 941 | "@executable_path/Frameworks", 942 | ); 943 | PRODUCT_BUNDLE_IDENTIFIER = com.bettycc.retry; 944 | PRODUCT_NAME = "$(TARGET_NAME)"; 945 | SWIFT_VERSION = 4.0; 946 | TARGETED_DEVICE_FAMILY = "1,2"; 947 | }; 948 | name = Release; 949 | }; 950 | 42DA4DD520C8C86F002D161F /* Debug */ = { 951 | isa = XCBuildConfiguration; 952 | buildSettings = { 953 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 954 | BUNDLE_LOADER = "$(TEST_HOST)"; 955 | CODE_SIGN_STYLE = Automatic; 956 | DEVELOPMENT_TEAM = S833P2K5YV; 957 | INFOPLIST_FILE = ImageCrawlerTests/Info.plist; 958 | LD_RUNPATH_SEARCH_PATHS = ( 959 | "$(inherited)", 960 | "@executable_path/Frameworks", 961 | "@loader_path/Frameworks", 962 | ); 963 | PRODUCT_BUNDLE_IDENTIFIER = bettycc.com.ImageCrawlerTests; 964 | PRODUCT_NAME = "$(TARGET_NAME)"; 965 | SWIFT_VERSION = 4.0; 966 | TARGETED_DEVICE_FAMILY = "1,2"; 967 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ImageCrawler.app/ImageCrawler"; 968 | }; 969 | name = Debug; 970 | }; 971 | 42DA4DD620C8C86F002D161F /* Release */ = { 972 | isa = XCBuildConfiguration; 973 | buildSettings = { 974 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 975 | BUNDLE_LOADER = "$(TEST_HOST)"; 976 | CODE_SIGN_STYLE = Automatic; 977 | DEVELOPMENT_TEAM = S833P2K5YV; 978 | INFOPLIST_FILE = ImageCrawlerTests/Info.plist; 979 | LD_RUNPATH_SEARCH_PATHS = ( 980 | "$(inherited)", 981 | "@executable_path/Frameworks", 982 | "@loader_path/Frameworks", 983 | ); 984 | PRODUCT_BUNDLE_IDENTIFIER = bettycc.com.ImageCrawlerTests; 985 | PRODUCT_NAME = "$(TARGET_NAME)"; 986 | SWIFT_VERSION = 4.0; 987 | TARGETED_DEVICE_FAMILY = "1,2"; 988 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ImageCrawler.app/ImageCrawler"; 989 | }; 990 | name = Release; 991 | }; 992 | 42DA4DD820C8C86F002D161F /* Debug */ = { 993 | isa = XCBuildConfiguration; 994 | buildSettings = { 995 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 996 | CODE_SIGN_STYLE = Automatic; 997 | DEVELOPMENT_TEAM = S833P2K5YV; 998 | INFOPLIST_FILE = ImageCrawlerUITests/Info.plist; 999 | LD_RUNPATH_SEARCH_PATHS = ( 1000 | "$(inherited)", 1001 | "@executable_path/Frameworks", 1002 | "@loader_path/Frameworks", 1003 | ); 1004 | PRODUCT_BUNDLE_IDENTIFIER = bettycc.com.ImageCrawlerUITests; 1005 | PRODUCT_NAME = "$(TARGET_NAME)"; 1006 | SWIFT_VERSION = 4.0; 1007 | TARGETED_DEVICE_FAMILY = "1,2"; 1008 | TEST_TARGET_NAME = ImageCrawler; 1009 | }; 1010 | name = Debug; 1011 | }; 1012 | 42DA4DD920C8C86F002D161F /* Release */ = { 1013 | isa = XCBuildConfiguration; 1014 | buildSettings = { 1015 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 1016 | CODE_SIGN_STYLE = Automatic; 1017 | DEVELOPMENT_TEAM = S833P2K5YV; 1018 | INFOPLIST_FILE = ImageCrawlerUITests/Info.plist; 1019 | LD_RUNPATH_SEARCH_PATHS = ( 1020 | "$(inherited)", 1021 | "@executable_path/Frameworks", 1022 | "@loader_path/Frameworks", 1023 | ); 1024 | PRODUCT_BUNDLE_IDENTIFIER = bettycc.com.ImageCrawlerUITests; 1025 | PRODUCT_NAME = "$(TARGET_NAME)"; 1026 | SWIFT_VERSION = 4.0; 1027 | TARGETED_DEVICE_FAMILY = "1,2"; 1028 | TEST_TARGET_NAME = ImageCrawler; 1029 | }; 1030 | name = Release; 1031 | }; 1032 | 42EEC94720DCCFFA0009A6AC /* Debug */ = { 1033 | isa = XCBuildConfiguration; 1034 | buildSettings = { 1035 | CODE_SIGN_ENTITLEMENTS = TunnelProvider/TunnelProvider.entitlements; 1036 | CODE_SIGN_IDENTITY = "iPhone Developer"; 1037 | CODE_SIGN_STYLE = Automatic; 1038 | DEVELOPMENT_TEAM = S833P2K5YV; 1039 | FRAMEWORK_SEARCH_PATHS = ( 1040 | "$(inherited)", 1041 | "$(PROJECT_DIR)/Carthage/Build/iOS", 1042 | ); 1043 | INFOPLIST_FILE = TunnelProvider/Info.plist; 1044 | LD_RUNPATH_SEARCH_PATHS = ( 1045 | "$(inherited)", 1046 | "@executable_path/Frameworks", 1047 | "@executable_path/../../Frameworks", 1048 | ); 1049 | PRODUCT_BUNDLE_IDENTIFIER = com.bettycc.retry.tunnelprovider; 1050 | PRODUCT_NAME = "$(TARGET_NAME)"; 1051 | PROVISIONING_PROFILE_SPECIFIER = ""; 1052 | SKIP_INSTALL = YES; 1053 | SWIFT_VERSION = 4.0; 1054 | TARGETED_DEVICE_FAMILY = "1,2"; 1055 | }; 1056 | name = Debug; 1057 | }; 1058 | 42EEC94820DCCFFA0009A6AC /* Release */ = { 1059 | isa = XCBuildConfiguration; 1060 | buildSettings = { 1061 | CODE_SIGN_ENTITLEMENTS = TunnelProvider/TunnelProvider.entitlements; 1062 | CODE_SIGN_IDENTITY = "iPhone Developer"; 1063 | CODE_SIGN_STYLE = Automatic; 1064 | DEVELOPMENT_TEAM = S833P2K5YV; 1065 | FRAMEWORK_SEARCH_PATHS = ( 1066 | "$(inherited)", 1067 | "$(PROJECT_DIR)/Carthage/Build/iOS", 1068 | ); 1069 | INFOPLIST_FILE = TunnelProvider/Info.plist; 1070 | LD_RUNPATH_SEARCH_PATHS = ( 1071 | "$(inherited)", 1072 | "@executable_path/Frameworks", 1073 | "@executable_path/../../Frameworks", 1074 | ); 1075 | PRODUCT_BUNDLE_IDENTIFIER = com.bettycc.retry.tunnelprovider; 1076 | PRODUCT_NAME = "$(TARGET_NAME)"; 1077 | PROVISIONING_PROFILE_SPECIFIER = ""; 1078 | SKIP_INSTALL = YES; 1079 | SWIFT_VERSION = 4.0; 1080 | TARGETED_DEVICE_FAMILY = "1,2"; 1081 | }; 1082 | name = Release; 1083 | }; 1084 | /* End XCBuildConfiguration section */ 1085 | 1086 | /* Begin XCConfigurationList section */ 1087 | 42DA4DA220C8C86E002D161F /* Build configuration list for PBXProject "ImageCrawler" */ = { 1088 | isa = XCConfigurationList; 1089 | buildConfigurations = ( 1090 | 42DA4DCF20C8C86F002D161F /* Debug */, 1091 | 42DA4DD020C8C86F002D161F /* Release */, 1092 | ); 1093 | defaultConfigurationIsVisible = 0; 1094 | defaultConfigurationName = Release; 1095 | }; 1096 | 42DA4DD120C8C86F002D161F /* Build configuration list for PBXNativeTarget "ImageCrawler" */ = { 1097 | isa = XCConfigurationList; 1098 | buildConfigurations = ( 1099 | 42DA4DD220C8C86F002D161F /* Debug */, 1100 | 42DA4DD320C8C86F002D161F /* Release */, 1101 | ); 1102 | defaultConfigurationIsVisible = 0; 1103 | defaultConfigurationName = Release; 1104 | }; 1105 | 42DA4DD420C8C86F002D161F /* Build configuration list for PBXNativeTarget "ImageCrawlerTests" */ = { 1106 | isa = XCConfigurationList; 1107 | buildConfigurations = ( 1108 | 42DA4DD520C8C86F002D161F /* Debug */, 1109 | 42DA4DD620C8C86F002D161F /* Release */, 1110 | ); 1111 | defaultConfigurationIsVisible = 0; 1112 | defaultConfigurationName = Release; 1113 | }; 1114 | 42DA4DD720C8C86F002D161F /* Build configuration list for PBXNativeTarget "ImageCrawlerUITests" */ = { 1115 | isa = XCConfigurationList; 1116 | buildConfigurations = ( 1117 | 42DA4DD820C8C86F002D161F /* Debug */, 1118 | 42DA4DD920C8C86F002D161F /* Release */, 1119 | ); 1120 | defaultConfigurationIsVisible = 0; 1121 | defaultConfigurationName = Release; 1122 | }; 1123 | 42EEC94620DCCFFA0009A6AC /* Build configuration list for PBXNativeTarget "TunnelProvider" */ = { 1124 | isa = XCConfigurationList; 1125 | buildConfigurations = ( 1126 | 42EEC94720DCCFFA0009A6AC /* Debug */, 1127 | 42EEC94820DCCFFA0009A6AC /* Release */, 1128 | ); 1129 | defaultConfigurationIsVisible = 0; 1130 | defaultConfigurationName = Release; 1131 | }; 1132 | /* End XCConfigurationList section */ 1133 | }; 1134 | rootObject = 42DA4D9F20C8C86E002D161F /* Project object */; 1135 | } 1136 | -------------------------------------------------------------------------------- /ImageCrawler.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ImageCrawler.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ImageCrawler.xcodeproj/project.xcworkspace/xcuserdata/cc.xcuserdatad/IDEFindNavigatorScopes.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ImageCrawler.xcodeproj/project.xcworkspace/xcuserdata/cc.xcuserdatad/xcdebugger/Expressions.xcexplist: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /ImageCrawler.xcodeproj/xcshareddata/xcschemes/CrawlerTunnelProvider.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 6 | 9 | 10 | 16 | 22 | 23 | 24 | 30 | 36 | 37 | 38 | 39 | 40 | 45 | 46 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 69 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 89 | 91 | 97 | 98 | 99 | 100 | 102 | 103 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /ImageCrawler.xcodeproj/xcuserdata/cc.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /ImageCrawler.xcodeproj/xcuserdata/cc.xcuserdatad/xcschemes/ImageCrawler.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /ImageCrawler.xcodeproj/xcuserdata/cc.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | CrawlerTunnelProvider.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 5 11 | 12 | ImageCrawler.xcscheme 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 42DA4DA620C8C86E002D161F 21 | 22 | primary 23 | 24 | 25 | 42EEC93C20DCCFFA0009A6AC 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ImageCrawler/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/7.\/ Copyright © 2018 Frank Cheng. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | import Switch 10 | import NetworkExtension 11 | import NEKit 12 | import CocoaLumberjackSwift 13 | import RealmSwift 14 | 15 | @UIApplicationMain 16 | class AppDelegate: UIResponder, UIApplicationDelegate { 17 | 18 | var window: UIWindow? 19 | 20 | 21 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 22 | // Override point for customization after application launch. 23 | DDLog.removeAllLoggers() 24 | DDLog.add(DDTTYLogger.sharedInstance, with: .info) 25 | 26 | print("application") 27 | let manager = NetworkManager() 28 | manager.startVPN { (manager, error) in 29 | print(error) 30 | } 31 | 32 | return true 33 | } 34 | 35 | func applicationWillResignActive(_ application: UIApplication) { 36 | // 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. 37 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 38 | } 39 | 40 | func applicationDidEnterBackground(_ application: UIApplication) { 41 | // 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. 42 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 43 | } 44 | 45 | func applicationWillEnterForeground(_ application: UIApplication) { 46 | // 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. 47 | } 48 | 49 | func applicationDidBecomeActive(_ application: UIApplication) { 50 | // 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. 51 | 52 | // let record = RealmUtil.get().objects(RequestRecord.self).first! 53 | // let r = HarProvider().generate(record: record) 54 | // print(r) 55 | 56 | DebugUtil.restoreRealm() 57 | DebugUtil.copyRealm() 58 | 59 | } 60 | 61 | func applicationDidFinishLaunching(_ application: UIApplication) { 62 | 63 | } 64 | 65 | func applicationWillTerminate(_ application: UIApplication) { 66 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 67 | 68 | } 69 | 70 | } 71 | 72 | -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/Artboard@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/Artboard@2x.png -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/Artboard@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/Artboard@3x.png -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "icon_20pt@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "icon_20pt@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "icon_29pt@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "icon_29pt@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "icon_40pt@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "icon_40pt@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "Artboard@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Artboard@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "size" : "20x20", 53 | "idiom" : "ipad", 54 | "filename" : "icon_20pt.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "icon_20pt@2x-1.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "29x29", 65 | "idiom" : "ipad", 66 | "filename" : "icon_29pt.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "icon_29pt@2x-1.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "40x40", 77 | "idiom" : "ipad", 78 | "filename" : "icon_40pt.png", 79 | "scale" : "1x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "icon_40pt@2x-1.png", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "size" : "76x76", 89 | "idiom" : "ipad", 90 | "filename" : "icon_76pt.png", 91 | "scale" : "1x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "icon_76pt@2x.png", 97 | "scale" : "2x" 98 | }, 99 | { 100 | "size" : "83.5x83.5", 101 | "idiom" : "ipad", 102 | "filename" : "icon_83.5@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "1024x1024", 107 | "idiom" : "ios-marketing", 108 | "filename" : "Icon.png", 109 | "scale" : "1x" 110 | } 111 | ], 112 | "info" : { 113 | "version" : 1, 114 | "author" : "xcode" 115 | } 116 | } -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/Icon.png -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_20pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_20pt.png -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_20pt@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_20pt@2x-1.png -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_20pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_20pt@2x.png -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_20pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_20pt@3x.png -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_29pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_29pt.png -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_29pt@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_29pt@2x-1.png -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_29pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_29pt@2x.png -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_29pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_29pt@3x.png -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_40pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_40pt.png -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_40pt@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_40pt@2x-1.png -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_40pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_40pt@2x.png -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_40pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_40pt@3x.png -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_76pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_76pt.png -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_76pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_76pt@2x.png -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/AppIcon-1.appiconset/icon_83.5@2x.png -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/_ionicons_svg_ios-power.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_29pt@2x.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/_ionicons_svg_ios-power.imageset/icon_29pt@2x.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/_ionicons_svg_ios-power.imageset/icon_29pt@2x.pdf -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/_ionicons_svg_md-tv.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_29pt@2x.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/_ionicons_svg_md-tv.imageset/icon_29pt@2x.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/_ionicons_svg_md-tv.imageset/icon_29pt@2x.pdf -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/first.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "first.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/first.imageset/first.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/first.imageset/first.pdf -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/har_template.dataset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "data" : [ 7 | { 8 | "idiom" : "universal", 9 | "filename" : "sample.json", 10 | "universal-type-identifier" : "json" 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/har_template.dataset/sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "log": { 3 | "version": "1.2", 4 | "creator": { 5 | "name": "Charles Proxy", 6 | "version": "4.0" 7 | }, 8 | "entries": [ 9 | { 10 | "startedDateTime": "2017-08-23T10:24:02.450+08:00", 11 | "time": 3531, 12 | "request": { 13 | "method": "POST", 14 | "url": "http://api.xinpinget.com/timeline/listSegments?token=NR41jAXcEt0VeTo7YlDm8UXo", 15 | "httpVersion": "HTTP/1.1", 16 | "cookies": [ 17 | { 18 | "name": "gr_user_id", 19 | "value": "f9a5c22c-d035-44df-8366-d55496a92051" 20 | } 21 | ], 22 | "headers": [ 23 | { 24 | "name": "Host", 25 | "value": "api.xinpinget.com" 26 | }, 27 | { 28 | "name": "Content-Type", 29 | "value": "application/x-www-form-urlencoded" 30 | }, 31 | { 32 | "name": "X-UUID", 33 | "value": "37954528-80AC-4CE1-9018-B118240B5965" 34 | }, 35 | { 36 | "name": "Cookie", 37 | "value": "gr_user_id=f9a5c22c-d035-44df-8366-d55496a92051" 38 | }, 39 | { 40 | "name": "Connection", 41 | "value": "keep-alive" 42 | }, 43 | { 44 | "name": "Accept", 45 | "value": "*/*" 46 | }, 47 | { 48 | "name": "User-Agent", 49 | "value": "MarkDaily/4.2.0 (iPhone; iOS 11.0; Scale/2.00)" 50 | }, 51 | { 52 | "name": "Accept-Language", 53 | "value": "en-CN;q=1, zh-Hans-CN;q=0.9, ja-JP;q=0.8" 54 | }, 55 | { 56 | "name": "Accept-Encoding", 57 | "value": "gzip, deflate" 58 | }, 59 | { 60 | "name": "Content-Length", 61 | "value": "0" 62 | } 63 | ], 64 | "queryString": [ 65 | { 66 | "name": "token", 67 | "value": "NR41jAXcEt0VeTo7YlDm8UXo" 68 | } 69 | ], 70 | "postData": { 71 | "mimeType": "application/x-www-form-urlencoded", 72 | "params": [] 73 | }, 74 | "headersSize": 455, 75 | "bodySize": 0 76 | }, 77 | "response": { 78 | "_charlesStatus": "COMPLETE", 79 | "status": 200, 80 | "statusText": "OK", 81 | "httpVersion": "HTTP/1.1", 82 | "cookies": [], 83 | "headers": [ 84 | { 85 | "name": "Server", 86 | "value": "nginx/1.8.1" 87 | }, 88 | { 89 | "name": "Date", 90 | "value": "Wed, 23 Aug 2017 02:24:05 GMT" 91 | }, 92 | { 93 | "name": "Content-Type", 94 | "value": "application/json; charset=utf-8" 95 | }, 96 | { 97 | "name": "Content-Length", 98 | "value": "23839" 99 | }, 100 | { 101 | "name": "X-Powered-By", 102 | "value": "Express" 103 | }, 104 | { 105 | "name": "Access-Control-Allow-Origin", 106 | "value": "*" 107 | }, 108 | { 109 | "name": "Cache-Control", 110 | "value": "no-cache" 111 | }, 112 | { 113 | "name": "X-Upstream", 114 | "value": "10.10.132.201:3000" 115 | }, 116 | { 117 | "name": "Proxy-Connection", 118 | "value": "Keep-alive" 119 | } 120 | ], 121 | "content": { 122 | "size": 23839, 123 | "mimeType": "application/json; charset=utf-8", 124 | "text": "content size" 125 | }, 126 | "redirectURL": null, 127 | "headersSize": 283, 128 | "bodySize": 23839 129 | }, 130 | "serverIPAddress": "123.59.59.234", 131 | "cache": {}, 132 | "timings": { 133 | "dns": 1, 134 | "connect": 3106, 135 | "ssl": -1, 136 | "send": 2, 137 | "wait": 383, 138 | "receive": 39 139 | } 140 | } 141 | ] 142 | } 143 | } -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/second.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "second.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /ImageCrawler/Assets.xcassets/second.imageset/second.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/ImageCrawler/Assets.xcassets/second.imageset/second.pdf -------------------------------------------------------------------------------- /ImageCrawler/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 | -------------------------------------------------------------------------------- /ImageCrawler/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 | 37 | 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 | 86 | 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 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 184 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 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 | 329 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 353 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 381 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 405 | 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 | 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 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 525 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 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 | -------------------------------------------------------------------------------- /ImageCrawler/ImageCrawler.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.networking.networkextension 6 | 7 | packet-tunnel-provider 8 | 9 | com.apple.security.application-groups 10 | 11 | group.com.bettycc.retry 12 | 13 | keychain-access-groups 14 | 15 | $(AppIdentifierPrefix)com.bettycc.retry 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /ImageCrawler/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | zh_CN 7 | CFBundleDisplayName 8 | 再试一次 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 0.2 21 | CFBundleVersion 22 | 6 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UIStatusBarTintParameters 34 | 35 | UINavigationBar 36 | 37 | Style 38 | UIBarStyleDefault 39 | Translucent 40 | 41 | 42 | 43 | UISupportedInterfaceOrientations 44 | 45 | UIInterfaceOrientationPortrait 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | UISupportedInterfaceOrientations~ipad 50 | 51 | UIInterfaceOrientationPortrait 52 | UIInterfaceOrientationPortraitUpsideDown 53 | UIInterfaceOrientationLandscapeLeft 54 | UIInterfaceOrientationLandscapeRight 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /ImageCrawler/Models/RequestRecord.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RequestRecord.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/19. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RealmSwift 11 | 12 | class HttpEntity:Object { 13 | @objc dynamic var header: String? = nil 14 | @objc dynamic var payload: String? = nil 15 | @objc dynamic var size: Int = 0 16 | 17 | func parseHost() -> String { 18 | let headers = parseHeaders() 19 | return headers["Host"] ?? "" 20 | } 21 | 22 | func parseField(field: String) -> String { 23 | let headers = parseHeaders() 24 | return headers[field] ?? "" 25 | } 26 | 27 | private func parseHeaders() -> [String: String] { 28 | if let header = header { 29 | return header.split(separator: "\r\n").filter { (line) -> Bool in 30 | line.contains(":")} 31 | .map{$0.split(separator: ":")} 32 | .reduce([String:String]()) { 33 | (d, splits) in 34 | var d = d 35 | d[String(splits[0])] = String(splits[1]).trimmingCharacters(in: CharacterSet(charactersIn: " ")) 36 | return d 37 | } 38 | } 39 | 40 | return [:] 41 | } 42 | } 43 | 44 | class ResponseEntity:HttpEntity { 45 | } 46 | 47 | class RequestEntity:HttpEntity { 48 | } 49 | 50 | 51 | class RequestRecord: Object { 52 | @objc dynamic var tunnelId: String? = nil 53 | @objc dynamic var date: Date? = Date() 54 | @objc dynamic var request: RequestEntity? = nil 55 | @objc dynamic var response: ResponseEntity? = nil 56 | } 57 | 58 | -------------------------------------------------------------------------------- /ImageCrawler/SecondViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/7. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Switch 11 | import NetworkExtension 12 | import NEKit 13 | import CocoaLumberjackSwift 14 | 15 | class SwitchViewController: UIViewController { 16 | 17 | @IBOutlet weak var `switch`: Switch! 18 | 19 | var targetManager:NEVPNManager = NEVPNManager.shared() 20 | 21 | override func viewDidLoad() { 22 | super.viewDidLoad() 23 | // Do any additional setup after loading the view, typically from a nib. 24 | } 25 | 26 | 27 | override func didReceiveMemoryWarning() { 28 | super.didReceiveMemoryWarning() 29 | // Dispose of any resources that can be recreated. 30 | } 31 | 32 | var server:GCDHTTPProxyServer? 33 | var socks5Proxy:GCDSOCKS5ProxyServer? 34 | 35 | @IBAction func toggle(_ sender: Switch) { 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /ImageCrawler/TEstTableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TEstTableViewController.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/20. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TEstTableViewController: UITableViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | // Uncomment the following line to preserve selection between presentations 17 | // self.clearsSelectionOnViewWillAppear = false 18 | 19 | // Uncomment the following line to display an Edit button in the navigation bar for this view controller. 20 | // self.navigationItem.rightBarButtonItem = self.editButtonItem 21 | } 22 | 23 | override func didReceiveMemoryWarning() { 24 | super.didReceiveMemoryWarning() 25 | // Dispose of any resources that can be recreated. 26 | } 27 | 28 | // MARK: - Table view data source 29 | 30 | override func numberOfSections(in tableView: UITableView) -> Int { 31 | // #warning Incomplete implementation, return the number of sections 32 | return 0 33 | } 34 | 35 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 36 | // #warning Incomplete implementation, return the number of rows 37 | return 0 38 | } 39 | 40 | /* 41 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 42 | let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) 43 | 44 | // Configure the cell... 45 | 46 | return cell 47 | } 48 | */ 49 | 50 | /* 51 | // Override to support conditional editing of the table view. 52 | override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { 53 | // Return false if you do not want the specified item to be editable. 54 | return true 55 | } 56 | */ 57 | 58 | /* 59 | // Override to support editing the table view. 60 | override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { 61 | if editingStyle == .delete { 62 | // Delete the row from the data source 63 | tableView.deleteRows(at: [indexPath], with: .fade) 64 | } else if editingStyle == .insert { 65 | // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view 66 | } 67 | } 68 | */ 69 | 70 | /* 71 | // Override to support rearranging the table view. 72 | override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) { 73 | 74 | } 75 | */ 76 | 77 | /* 78 | // Override to support conditional rearranging of the table view. 79 | override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { 80 | // Return false if you do not want the item to be re-orderable. 81 | return true 82 | } 83 | */ 84 | 85 | /* 86 | // MARK: - Navigation 87 | 88 | // In a storyboard-based application, you will often want to do a little preparation before navigation 89 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 90 | // Get the new view controller using segue.destinationViewController. 91 | // Pass the selected object to the new view controller. 92 | } 93 | */ 94 | 95 | } 96 | -------------------------------------------------------------------------------- /ImageCrawler/Utils/DebugUtil.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DebugUtils.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/24. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RealmSwift 11 | 12 | class DebugUtil { 13 | static func restoreRealm() { 14 | let fileManager = FileManager.default 15 | let restoreFile: URL = (fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!).appendingPathComponent("restore.realm") 16 | if fileManager.fileExists(atPath: restoreFile.path) { 17 | 18 | let targetFile: URL = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.com.bettycc.retry")!.appendingPathComponent(RealmUtil.realmFileName) 19 | 20 | if fileManager.fileExists(atPath: targetFile.path) { 21 | try! fileManager.removeItem(at: targetFile) 22 | } 23 | 24 | try! fileManager.copyItem(at: restoreFile, to: targetFile) 25 | try! fileManager.removeItem(at: restoreFile) 26 | 27 | } 28 | } 29 | 30 | 31 | static func copyRealm() { 32 | let fileManager = FileManager.default 33 | 34 | let destination: URL = (fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!).appendingPathComponent("SharedRealm.realm") 35 | 36 | do { 37 | try fileManager.removeItem(at: destination) 38 | } catch { 39 | } 40 | 41 | 42 | let source: URL = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.com.bettycc.retry")!.appendingPathComponent(RealmUtil.realmFileName) 43 | try! fileManager.copyItem(at: source, to: destination) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ImageCrawler/Utils/HarProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HarProvider.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/29. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import SwiftyJSON 12 | 13 | class HarProvider { 14 | 15 | var templateJson: JSON! 16 | 17 | init() { 18 | let asset = NSDataAsset(name: "har_template", bundle: Bundle.main) 19 | templateJson = try! JSON(data: asset!.data) 20 | } 21 | 22 | func generate(record: RequestRecord) -> String { 23 | return templateJson!.string! 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ImageCrawler/Utils/NetworkManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkManager.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/22. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import NetworkExtension 11 | 12 | class NetworkManager { 13 | 14 | 15 | public func startVPN(_ complete: ((NETunnelProviderManager?, Error?) -> Void)? = nil) { 16 | startVPNWithOptions(nil, complete: complete) 17 | } 18 | 19 | fileprivate func startVPNWithOptions(_ options: [String : NSObject]?, complete: ((NETunnelProviderManager?, Error?) -> Void)? = nil) { 20 | // Load provider 21 | loadAndCreateProviderManager { (manager, error) -> Void in 22 | if let error = error { 23 | complete?(nil, error) 24 | }else{ 25 | guard let manager = manager else { 26 | complete?(nil, error) 27 | return 28 | } 29 | if manager.connection.status == .disconnected || manager.connection.status == .invalid { 30 | do { 31 | try manager.connection.startVPNTunnel(options: options) 32 | // self.addVPNStatusObserver() 33 | complete?(manager, nil) 34 | }catch { 35 | complete?(nil, error) 36 | } 37 | }else{ 38 | // self.addVPNStatusObserver() 39 | complete?(manager, nil) 40 | } 41 | } 42 | } 43 | } 44 | 45 | 46 | func stop() { 47 | NETunnelProviderManager.loadAllFromPreferences(completionHandler: { (managers, error) in 48 | if let managers = managers { 49 | if managers.count > 0 && managers.first!.connection.status == .connected { 50 | managers.first?.connection.stopVPNTunnel() 51 | } 52 | } 53 | }) 54 | } 55 | 56 | } 57 | 58 | extension NetworkManager { 59 | 60 | fileprivate func loadAndCreateProviderManager(_ complete: @escaping (NETunnelProviderManager?, Error?) -> Void ) { 61 | NETunnelProviderManager.loadAllFromPreferences { [unowned self] (managers, error) -> Void in 62 | if let managers = managers { 63 | let manager: NETunnelProviderManager 64 | if managers.count > 0 { 65 | manager = managers[0] 66 | }else{ 67 | manager = NETunnelProviderManager() 68 | manager.protocolConfiguration = NETunnelProviderProtocol() 69 | } 70 | 71 | let configuration = manager.protocolConfiguration as! NETunnelProviderProtocol 72 | configuration.serverAddress = "ImageCrawler" 73 | configuration.providerBundleIdentifier = "com.bettycc.retry.tunnelprovider" 74 | manager.isEnabled = true 75 | manager.localizedDescription = "ImageCrawler" 76 | 77 | manager.saveToPreferences(completionHandler: { (error) -> Void in 78 | if let error = error { 79 | complete(nil, error) 80 | }else{ 81 | manager.loadFromPreferences(completionHandler: { (error) -> Void in 82 | if let error = error { 83 | complete(nil, error) 84 | }else{ 85 | complete(manager, nil) 86 | } 87 | }) 88 | } 89 | }) 90 | }else{ 91 | complete(nil, error) 92 | } 93 | } 94 | } 95 | 96 | public func loadProviderManager(_ complete: @escaping (NETunnelProviderManager?) -> Void) { 97 | NETunnelProviderManager.loadAllFromPreferences { (managers, error) -> Void in 98 | if let managers = managers { 99 | if managers.count > 0 { 100 | let manager = managers[0] 101 | complete(manager) 102 | return 103 | } 104 | } 105 | complete(nil) 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /ImageCrawler/Utils/RealmUtil.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RealmUtil.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/23. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RealmSwift 11 | 12 | class RealmUtil { 13 | static let realmFileName = "SharedRealm" + (Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String) + "." + (Bundle.main.infoDictionary!["CFBundleVersion"] as! String) + ".realm" 14 | 15 | static func get() -> Realm { 16 | 17 | let sharedContainerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.bettycc.retry")! 18 | print("--------------share directory", sharedContainerURL) 19 | let realmURL = sharedContainerURL.appendingPathComponent(realmFileName) 20 | let config: Realm.Configuration = Realm.Configuration(fileURL: realmURL) 21 | Realm.Configuration.defaultConfiguration = config 22 | return try! Realm(configuration: config) 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ImageCrawler/Utils/TableSegment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TableSegment.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/25. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | protocol TableSegment { 13 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 14 | func numberOfSections(in tableView: UITableView) -> Int 15 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 16 | } 17 | -------------------------------------------------------------------------------- /ImageCrawler/ViewControllers/DetailController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DetailController.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/21. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import RealmSwift 11 | 12 | class DetailController: UIViewController { 13 | 14 | var record: RequestRecord? 15 | 16 | @IBOutlet weak var segmentControl: UISegmentedControl! 17 | @IBOutlet weak var summaryView: UIView! 18 | @IBOutlet weak var requestView: UIView! 19 | @IBOutlet weak var responseView: UIView! 20 | var segmentViews: [UIView]! 21 | 22 | var segmentControllers: [String: SegmentController]! = [String:SegmentController]() 23 | 24 | fileprivate func selectSegment(_ sender: UISegmentedControl) { 25 | for i in 0.. NSAttributedString? { 57 | do { 58 | //Should format json data. 59 | let highlightr = Highlightr() 60 | highlightr?.setTheme(to: "solarized-light") 61 | 62 | let d = bodyData.data(using: .utf8) 63 | let obj = try JSONSerialization.jsonObject(with: d!, options: .allowFragments) 64 | let jsonData = try JSONSerialization.data(withJSONObject: obj, options: .prettyPrinted) 65 | let formattedString = String(bytes: jsonData, encoding: .utf8) 66 | 67 | return highlightr!.highlight(formattedString!, as: "json", fastRender: true) 68 | } catch { 69 | print("data", bodyData) 70 | print("error", error.localizedDescription) 71 | } 72 | 73 | return NSAttributedString(string:self.bodyData) 74 | } 75 | 76 | override func didReceiveMemoryWarning() { 77 | super.didReceiveMemoryWarning() 78 | // Dispose of any resources that can be recreated. 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /ImageCrawler/ViewControllers/RecordController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RecordController.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/20. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import RealmSwift 11 | import SwiftDate 12 | 13 | class RecordController: UITableViewController { 14 | 15 | var records: Results? 16 | 17 | let realm = RealmUtil.get() 18 | 19 | var token:NotificationToken? 20 | @IBOutlet var table: UITableView! 21 | 22 | func loadRecords() { 23 | records = realm.objects(RequestRecord.self).sorted(byKeyPath: "date", ascending: false) 24 | 25 | } 26 | 27 | override func viewDidLoad() { 28 | super.viewDidLoad() 29 | 30 | loadRecords() 31 | token = records!.observe { [weak self] changes in 32 | self?.loadRecords() 33 | self?.table.reloadData() 34 | } 35 | } 36 | 37 | override func didReceiveMemoryWarning() { 38 | super.didReceiveMemoryWarning() 39 | // Dispose of any resources that can be recreated. 40 | } 41 | 42 | // MARK: - Table view data source 43 | 44 | override func numberOfSections(in tableView: UITableView) -> Int { 45 | // #warning Incomplete implementation, return the number of sections 46 | return 1 47 | } 48 | 49 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 50 | // #warning Incomplete implementation, return the number of rows 51 | if let count = records?.count { 52 | return count 53 | } else { 54 | return 0 55 | } 56 | } 57 | 58 | override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { 59 | return "请求" 60 | } 61 | 62 | override func viewWillAppear(_ animated: Bool) { 63 | loadRecords() 64 | } 65 | 66 | 67 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 68 | let cell = tableView.dequeueReusableCell(withIdentifier: "record", for: indexPath) 69 | 70 | if let record = records?[indexPath.item], let request = record.request { 71 | cell.textLabel?.text = request.parseHost() 72 | cell.detailTextLabel?.text = DateInRegion(absoluteDate: record.date!).string(dateStyle: .medium, timeStyle: .medium) 73 | } 74 | 75 | return cell 76 | } 77 | 78 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 79 | if segue.identifier == "detail" { 80 | let detailController = segue.destination as! DetailController 81 | if let record = records?[table.indexPathForSelectedRow!.item] { 82 | detailController.record = record 83 | } 84 | } 85 | } 86 | 87 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 88 | tableView.deselectRow(at: indexPath, animated: false) 89 | } 90 | 91 | deinit { 92 | token?.invalidate() 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /ImageCrawler/ViewControllers/RequestSegmentController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RequestSegmentController.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/25. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import UIKit 12 | import SwiftDate 13 | 14 | class RequestSegmentController: SegmentController { 15 | 16 | @IBOutlet weak var header: UILabel! 17 | @IBOutlet weak var type: UILabel! 18 | 19 | override func updateViews() { 20 | header.text = self.record.request?.header 21 | type.text = self.record.request?.parseField(field: "Content-Type") 22 | tableView.reloadData() 23 | } 24 | 25 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 26 | if segue.identifier == "body" { 27 | let bodyController = segue.destination as! HttpBodyController 28 | if let request = record.request { 29 | bodyController.bodyData = request.payload 30 | bodyController.setType(contentType: request.parseField(field: "Content-Type")) 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ImageCrawler/ViewControllers/ResponseSegmentController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RequestSegmentController.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/25. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import UIKit 12 | import SwiftDate 13 | 14 | class ResponseSegmentController: SegmentController { 15 | 16 | @IBOutlet weak var header: UILabel! 17 | @IBOutlet weak var type: UILabel! 18 | 19 | override func updateViews() { 20 | header.text = self.record.response?.header 21 | type.text = self.record.response?.parseField(field: "Content-Type") 22 | tableView.reloadData() 23 | } 24 | 25 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 26 | if segue.identifier == "body" { 27 | let bodyController = segue.destination as! HttpBodyController 28 | if let response = record.response { 29 | bodyController.bodyData = response.payload 30 | bodyController.setType(contentType: response.parseField(field: "Content-Type")) 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ImageCrawler/ViewControllers/SegmentController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SegmentController.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/25. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SegmentController: UITableViewController { 12 | 13 | var record: RequestRecord! { 14 | didSet { 15 | self.updateViews() 16 | } 17 | } 18 | 19 | func updateViews() { 20 | print("update in segment") 21 | } 22 | 23 | 24 | override func viewDidLoad() { 25 | super.viewDidLoad() 26 | 27 | // Uncomment the following line to preserve selection between presentations 28 | // self.clearsSelectionOnViewWillAppear = false 29 | 30 | // Uncomment the following line to display an Edit button in the navigation bar for this view controller. 31 | // self.navigationItem.rightBarButtonItem = self.editButtonItem 32 | } 33 | 34 | override func didReceiveMemoryWarning() { 35 | super.didReceiveMemoryWarning() 36 | // Dispose of any resources that can be recreated. 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ImageCrawler/ViewControllers/SummarySegmentController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SummarySegmentController.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/25. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import SwiftDate 12 | 13 | class SummarySegmentController: SegmentController { 14 | 15 | @IBOutlet weak var date: UILabel! 16 | 17 | @IBOutlet weak var responseSize: UILabel! 18 | @IBOutlet weak var requestSize: UILabel! 19 | 20 | override func updateViews() { 21 | print("update in summary") 22 | let dateString = DateInRegion(absoluteDate: self.record.date!).string(dateStyle: .medium, timeStyle: .medium) 23 | date.text = dateString 24 | 25 | if let request = self.record.request { 26 | requestSize.text = formatByteCount(size: request.size) 27 | } 28 | 29 | if let response = self.record.response { 30 | responseSize.text = formatByteCount(size: response.size) 31 | } 32 | 33 | 34 | tableView.reloadData() 35 | } 36 | 37 | 38 | func formatByteCount(size: Int) -> String { 39 | let bcf = ByteCountFormatter() 40 | bcf.allowedUnits = [.useKB, .useMB, .useBytes] 41 | return bcf.string(fromByteCount: Int64(size)) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ImageCrawler/ViewControllers/SwitcherController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwitcherController.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/26. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Switch 11 | 12 | class SwitcherController: UIViewController { 13 | 14 | var networkManager = NetworkManager() 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | 19 | // Do any additional setup after loading the view. 20 | } 21 | 22 | override func didReceiveMemoryWarning() { 23 | super.didReceiveMemoryWarning() 24 | // Dispose of any resources that can be recreated. 25 | } 26 | 27 | @IBAction func onSwitchChanged(_ sender: Switch) { 28 | let off = sender.rightSelected 29 | if off { 30 | networkManager.stop() 31 | } else { 32 | networkManager.startVPN { (manager, error) in 33 | return 34 | } 35 | } 36 | } 37 | 38 | /* 39 | // MARK: - Navigation 40 | 41 | // In a storyboard-based application, you will often want to do a little preparation before navigation 42 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 43 | // Get the new view controller using segue.destinationViewController. 44 | // Pass the selected object to the new view controller. 45 | } 46 | */ 47 | 48 | } 49 | -------------------------------------------------------------------------------- /ImageCrawler/Views/DetailContentCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DetailContentCell.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/21. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class DetailInfoCell: UITableViewCell { 12 | 13 | @IBOutlet weak var key: UILabel! 14 | 15 | @IBOutlet weak var value: UILabel! 16 | 17 | 18 | override func awakeFromNib() { 19 | super.awakeFromNib() 20 | // Initialization code 21 | } 22 | 23 | override func setSelected(_ selected: Bool, animated: Bool) { 24 | super.setSelected(selected, animated: animated) 25 | 26 | // Configure the view for the selected state 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /ImageCrawler/Views/RecordCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RecordCell.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/20. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class RecordCell: UITableViewCell { 12 | 13 | @IBOutlet weak var url: UILabel! 14 | @IBOutlet weak var date: UILabel! 15 | 16 | override func awakeFromNib() { 17 | super.awakeFromNib() 18 | // Initialization code 19 | } 20 | 21 | override func setSelected(_ selected: Bool, animated: Bool) { 22 | super.setSelected(selected, animated: animated) 23 | 24 | // Configure the view for the selected state 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /ImageCrawlerTests/ImageCrawlerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageCrawlerTests.swift 3 | // ImageCrawlerTests 4 | // 5 | // Created by Frank Cheng on 2018/6/7. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import ImageCrawler 11 | 12 | class ImageCrawlerTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /ImageCrawlerTests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ImageCrawlerUITests/ImageCrawlerUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageCrawlerUITests.swift 3 | // ImageCrawlerUITests 4 | // 5 | // Created by Frank Cheng on 2018/6/7. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class ImageCrawlerUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | 18 | // In UI tests it is usually best to stop immediately when a failure occurs. 19 | continueAfterFailure = false 20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 21 | XCUIApplication().launch() 22 | 23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 24 | } 25 | 26 | override func tearDown() { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | super.tearDown() 29 | } 30 | 31 | func testExample() { 32 | // Use recording to get started writing UI tests. 33 | // Use XCTAssert and related functions to verify your tests produce the correct results. 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /ImageCrawlerUITests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Retry 2 | ![](./icon.png) 3 | 4 | 中文名: 再试一次 5 | 6 | 抓包工具,可以抓其他 app 的 http 的包. 使用 NetworkExtension 来配置代理,使用 NEKit 来启动 Http Proxy Server 7 | 8 | ## 截图 9 | 10 | ![](./art/s1.png) 11 | ![](./art/s2.png) 12 | ![](./art/s3.png) 13 | ![](./art/s4.png) 14 | 15 | 16 | -------------------------------------------------------------------------------- /TunnelProvider/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | TunnelProvider 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 | 0.2 21 | CFBundleVersion 22 | 6 23 | NSExtension 24 | 25 | NSExtensionPointIdentifier 26 | com.apple.networkextension.packet-tunnel 27 | NSExtensionPrincipalClass 28 | $(PRODUCT_MODULE_NAME).PacketTunnelProvider 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /TunnelProvider/PacketTunnelProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PacketTunnelProvider.swift 3 | // CrawlerTunnelProvider 4 | // 5 | // Created by Frank Cheng on 2018/6/22. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import NetworkExtension 10 | import NEKit 11 | import RealmSwift 12 | 13 | class PacketTunnelProvider: NEPacketTunnelProvider { 14 | 15 | var proxyServer: ProxyServer! 16 | var debugProxyServer: ProxyServer! 17 | 18 | override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) { 19 | // Add code here to start the process of connecting the tunnel. 20 | NSLog("start tunnel-0-----------------") 21 | 22 | 23 | let networkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.1") 24 | networkSettings.mtu = 1500 25 | 26 | let proxySettings = NEProxySettings() 27 | proxySettings.httpServer = NEProxyServer(address: "127.0.0.1", port: 9090) 28 | proxySettings.httpEnabled = true 29 | // proxySettings.httpsServer = NEProxyServer(address: "127.0.0;.1", port: 9090) 30 | // proxySettings.httpsEnabled = true 31 | // proxySettings.matchDomains = [""] 32 | // proxySettings.matchDomains = ["api.xinpinget.com"] 33 | proxySettings.matchDomains = [""] 34 | networkSettings.proxySettings = proxySettings 35 | 36 | networkSettings.dnsSettings = NEDNSSettings(servers: ["114.114.114.114"]) 37 | 38 | let ipv4Settings = NEIPv4Settings(addresses: ["192.169.89.1"], subnetMasks: ["255.255.255.0"]) 39 | networkSettings.ipv4Settings = ipv4Settings 40 | 41 | RawSocketFactory.TunnelProvider = self 42 | 43 | setTunnelNetworkSettings(networkSettings) { (error) in 44 | 45 | if let error = error { 46 | NSLog("++++++++++" + error.localizedDescription) 47 | } 48 | 49 | self.proxyServer = GCDHTTPProxyServer(address: IPAddress(fromString: "127.0.0.1"), port: 9090) 50 | self.debugProxyServer = GCDHTTPProxyServer(address: nil, port: 9091) 51 | 52 | ObserverFactory.currentFactory = ProxyObserverFactory() 53 | 54 | try! self.proxyServer.start() 55 | try! self.debugProxyServer.start() 56 | 57 | completionHandler(nil) 58 | NSLog("end") 59 | 60 | } 61 | 62 | } 63 | 64 | 65 | override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { 66 | // Add code here to start the process of stopping the tunnel. 67 | proxyServer.stop() 68 | debugProxyServer.stop() 69 | completionHandler() 70 | } 71 | 72 | override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) { 73 | // Add code here to handle the message. 74 | if let handler = completionHandler { 75 | handler(messageData) 76 | } 77 | } 78 | 79 | override func sleep(completionHandler: @escaping () -> Void) { 80 | // Add code here to get ready to sleep. 81 | completionHandler() 82 | } 83 | 84 | override func wake() { 85 | // Add code here to wake up. 86 | NSLog("start tunnel-0-----------------") 87 | 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /TunnelProvider/ProxyObserverFactory.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ServerObserver.swift 3 | // ImageCrawler 4 | // 5 | // Created by Frank Cheng on 2018/6/15. 6 | // Copyright © 2018 Frank Cheng. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RealmSwift 11 | import NEKit 12 | 13 | class ProxyObserverFactory : DebugObserverFactory { 14 | 15 | override func getObserverForTunnel(_ tunnel: Tunnel) -> Observer? { 16 | return ProxyTunnelObserver() 17 | } 18 | } 19 | 20 | class ProxyTunnelObserver: Observer { 21 | let manager = RecordManager() 22 | 23 | override open func signal(_ event: TunnelEvent) { 24 | switch event { 25 | case .proxySocketReadData(let data, let socket, let tunnel): 26 | manager.upsertRequest(data, socket, tunnel) 27 | case .adapterSocketReadData(let data, let socket, let tunnel): 28 | manager.upsertResponse(data, socket, tunnel) 29 | case .receivedRequest, 30 | .closed: 31 | break 32 | case .opened, 33 | .connectedToRemote, 34 | .updatingAdapterSocket: 35 | break 36 | case .closeCalled, 37 | .forceCloseCalled, 38 | .receivedReadySignal, 39 | .proxySocketWroteData, 40 | .adapterSocketWroteData: 41 | break 42 | } 43 | } 44 | } 45 | 46 | class RecordManager { 47 | 48 | let dataThreshold = 1024*1024 49 | 50 | func upsertResponse(_ data: Data, _ socket: AdapterSocket, _ tunnel: Tunnel) { 51 | guard data.count < dataThreshold else { 52 | return 53 | } 54 | 55 | let dataString: String = String(data: data, encoding: .utf8) ?? "" 56 | 57 | NSLog("response payload: \(dataString)") 58 | let tunnelId = extractTunnelId(tunnel) 59 | let realm = RealmUtil.get() 60 | let record = realm.objects(RequestRecord.self).filter("tunnelId = '\(tunnelId)'").first 61 | 62 | 63 | let splits = dataString.components(separatedBy: "\r\n\r\n") 64 | if let record = record { 65 | if splits.count == 2 { 66 | try! realm.write { 67 | let responseEntity: ResponseEntity = ResponseEntity() 68 | responseEntity.header = String(splits[0]) 69 | responseEntity.payload = String(splits[1]) 70 | responseEntity.size += data.count 71 | record.response = responseEntity 72 | } 73 | } else { 74 | try! realm.write { 75 | if let res = record.response, let payload = record.response?.payload { 76 | res.payload = payload + dataString 77 | res.size += data.count 78 | } 79 | } 80 | } 81 | } 82 | } 83 | 84 | fileprivate func extractTunnelId(_ tunnel: Tunnel) -> String { 85 | return String(ObjectIdentifier(tunnel).hashValue) 86 | } 87 | 88 | fileprivate func upsertRequest(_ data: Data, _ socket: ProxySocket, _ tunnel: Tunnel) { 89 | guard data.count < dataThreshold else { 90 | return 91 | } 92 | 93 | let dataString = String(data: data, encoding: .utf8) ?? "" 94 | 95 | let realm = RealmUtil.get() 96 | let tunnelId = extractTunnelId(tunnel) 97 | let record = realm.objects(RequestRecord.self).filter("tunnelId = '\(tunnelId)'").first ?? RequestRecord() 98 | try! realm.write { 99 | record.tunnelId = tunnelId 100 | 101 | let httpSocket = socket as! HTTPProxySocket 102 | record.request = record.request ?? RequestEntity() 103 | if (httpSocket.readStatusDescription == "waiting to send first header") { 104 | record.request?.header = dataString 105 | } else if (httpSocket.readStatusDescription == "reading content (forwarding)") { 106 | record.request?.payload = dataString 107 | } 108 | record.request?.size += data.count 109 | 110 | realm.add(record) 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /TunnelProvider/TunnelProvider.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.networking.networkextension 6 | 7 | packet-tunnel-provider 8 | 9 | com.apple.security.application-groups 10 | 11 | group.com.bettycc.retry 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /art/s1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/art/s1.png -------------------------------------------------------------------------------- /art/s2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/art/s2.png -------------------------------------------------------------------------------- /art/s3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/art/s3.png -------------------------------------------------------------------------------- /art/s4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/art/s4.png -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/icon.png -------------------------------------------------------------------------------- /icon.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/icon.sketch -------------------------------------------------------------------------------- /jj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufo22940268/Retry/0f1bc83d02625ed3819fdfe8332e8bbbbdd2e931/jj --------------------------------------------------------------------------------