├── README.md └── WebViewShare ├── WebViewShare.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── Cyan.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── Cyan.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── WebViewShare.xcscheme │ └── xcschememanagement.plist ├── WebViewShare ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── MonitorURLProtocol.h ├── MonitorURLProtocol.m ├── TableViewController.h ├── TableViewController.m ├── TestUIWebView.h ├── TestUIWebView.m ├── TestWKWebView.h ├── TestWKWebView.m ├── ViewController.h ├── ViewController.m ├── WKWebViewTracker.h ├── WKWebViewTracker.m ├── WebViewMonitor.framework │ ├── Headers │ │ ├── WebViewJavaScript_js.h │ │ └── WebViewMonitor.h │ ├── Info.plist │ ├── Modules │ │ └── module.modulemap │ ├── WebViewMonitor │ └── _CodeSignature │ │ ├── CodeDirectory │ │ ├── CodeRequirements │ │ ├── CodeRequirements-1 │ │ ├── CodeResources │ │ ├── CodeSignature │ │ └── CodeTopDirectory ├── WebViewTracker.h ├── WebViewTracker.m └── main.m ├── WebViewShareTests ├── Info.plist └── WebViewShareTests.m └── WebViewShareUITests ├── Info.plist └── WebViewShareUITests.m /README.md: -------------------------------------------------------------------------------- 1 | # WebView 2 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8743B1911CCF04CA001DC742 /* WebViewMonitor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8743B1901CCF04CA001DC742 /* WebViewMonitor.framework */; }; 11 | 8743B1941CCF1711001DC742 /* MonitorURLProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = 8743B1931CCF1711001DC742 /* MonitorURLProtocol.m */; }; 12 | 875B02611CCDF1D500A12299 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 875B02601CCDF1D500A12299 /* main.m */; }; 13 | 875B02641CCDF1D500A12299 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 875B02631CCDF1D500A12299 /* AppDelegate.m */; }; 14 | 875B026A1CCDF1D500A12299 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 875B02681CCDF1D500A12299 /* Main.storyboard */; }; 15 | 875B026C1CCDF1D500A12299 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 875B026B1CCDF1D500A12299 /* Assets.xcassets */; }; 16 | 875B026F1CCDF1D500A12299 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 875B026D1CCDF1D500A12299 /* LaunchScreen.storyboard */; }; 17 | 875B027A1CCDF1D500A12299 /* WebViewShareTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 875B02791CCDF1D500A12299 /* WebViewShareTests.m */; }; 18 | 875B02851CCDF1D500A12299 /* WebViewShareUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 875B02841CCDF1D500A12299 /* WebViewShareUITests.m */; }; 19 | 875B02941CCDFA2A00A12299 /* TableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 875B02931CCDFA2A00A12299 /* TableViewController.m */; }; 20 | 875B02981CCDFCA200A12299 /* TestUIWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 875B02971CCDFCA200A12299 /* TestUIWebView.m */; }; 21 | 875B029B1CCDFCBC00A12299 /* TestWKWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 875B029A1CCDFCBC00A12299 /* TestWKWebView.m */; }; 22 | 875B02A31CCE005F00A12299 /* WebViewTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 875B02A21CCE005F00A12299 /* WebViewTracker.m */; }; 23 | 875B02A61CCE026D00A12299 /* WKWebViewTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 875B02A51CCE026D00A12299 /* WKWebViewTracker.m */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXContainerItemProxy section */ 27 | 875B02761CCDF1D500A12299 /* PBXContainerItemProxy */ = { 28 | isa = PBXContainerItemProxy; 29 | containerPortal = 875B02541CCDF1D500A12299 /* Project object */; 30 | proxyType = 1; 31 | remoteGlobalIDString = 875B025B1CCDF1D500A12299; 32 | remoteInfo = WebViewShare; 33 | }; 34 | 875B02811CCDF1D500A12299 /* PBXContainerItemProxy */ = { 35 | isa = PBXContainerItemProxy; 36 | containerPortal = 875B02541CCDF1D500A12299 /* Project object */; 37 | proxyType = 1; 38 | remoteGlobalIDString = 875B025B1CCDF1D500A12299; 39 | remoteInfo = WebViewShare; 40 | }; 41 | /* End PBXContainerItemProxy section */ 42 | 43 | /* Begin PBXFileReference section */ 44 | 8743B1901CCF04CA001DC742 /* WebViewMonitor.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = WebViewMonitor.framework; sourceTree = ""; }; 45 | 8743B1921CCF1711001DC742 /* MonitorURLProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MonitorURLProtocol.h; sourceTree = ""; }; 46 | 8743B1931CCF1711001DC742 /* MonitorURLProtocol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MonitorURLProtocol.m; sourceTree = ""; }; 47 | 875B025C1CCDF1D500A12299 /* WebViewShare.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WebViewShare.app; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | 875B02601CCDF1D500A12299 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 49 | 875B02621CCDF1D500A12299 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 50 | 875B02631CCDF1D500A12299 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 51 | 875B02691CCDF1D500A12299 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 52 | 875B026B1CCDF1D500A12299 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 53 | 875B026E1CCDF1D500A12299 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 54 | 875B02701CCDF1D500A12299 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 55 | 875B02751CCDF1D500A12299 /* WebViewShareTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WebViewShareTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | 875B02791CCDF1D500A12299 /* WebViewShareTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WebViewShareTests.m; sourceTree = ""; }; 57 | 875B027B1CCDF1D500A12299 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | 875B02801CCDF1D500A12299 /* WebViewShareUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WebViewShareUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | 875B02841CCDF1D500A12299 /* WebViewShareUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WebViewShareUITests.m; sourceTree = ""; }; 60 | 875B02861CCDF1D500A12299 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 61 | 875B02921CCDFA2A00A12299 /* TableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TableViewController.h; sourceTree = ""; }; 62 | 875B02931CCDFA2A00A12299 /* TableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TableViewController.m; sourceTree = ""; }; 63 | 875B02961CCDFCA200A12299 /* TestUIWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestUIWebView.h; sourceTree = ""; }; 64 | 875B02971CCDFCA200A12299 /* TestUIWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestUIWebView.m; sourceTree = ""; }; 65 | 875B02991CCDFCBC00A12299 /* TestWKWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestWKWebView.h; sourceTree = ""; }; 66 | 875B029A1CCDFCBC00A12299 /* TestWKWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestWKWebView.m; sourceTree = ""; }; 67 | 875B02A11CCE005F00A12299 /* WebViewTracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewTracker.h; sourceTree = ""; }; 68 | 875B02A21CCE005F00A12299 /* WebViewTracker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewTracker.m; sourceTree = ""; }; 69 | 875B02A41CCE026D00A12299 /* WKWebViewTracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKWebViewTracker.h; sourceTree = ""; }; 70 | 875B02A51CCE026D00A12299 /* WKWebViewTracker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WKWebViewTracker.m; sourceTree = ""; }; 71 | /* End PBXFileReference section */ 72 | 73 | /* Begin PBXFrameworksBuildPhase section */ 74 | 875B02591CCDF1D500A12299 /* Frameworks */ = { 75 | isa = PBXFrameworksBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | 8743B1911CCF04CA001DC742 /* WebViewMonitor.framework in Frameworks */, 79 | ); 80 | runOnlyForDeploymentPostprocessing = 0; 81 | }; 82 | 875B02721CCDF1D500A12299 /* Frameworks */ = { 83 | isa = PBXFrameworksBuildPhase; 84 | buildActionMask = 2147483647; 85 | files = ( 86 | ); 87 | runOnlyForDeploymentPostprocessing = 0; 88 | }; 89 | 875B027D1CCDF1D500A12299 /* Frameworks */ = { 90 | isa = PBXFrameworksBuildPhase; 91 | buildActionMask = 2147483647; 92 | files = ( 93 | ); 94 | runOnlyForDeploymentPostprocessing = 0; 95 | }; 96 | /* End PBXFrameworksBuildPhase section */ 97 | 98 | /* Begin PBXGroup section */ 99 | 875B02531CCDF1D400A12299 = { 100 | isa = PBXGroup; 101 | children = ( 102 | 875B025E1CCDF1D500A12299 /* WebViewShare */, 103 | 875B02781CCDF1D500A12299 /* WebViewShareTests */, 104 | 875B02831CCDF1D500A12299 /* WebViewShareUITests */, 105 | 875B025D1CCDF1D500A12299 /* Products */, 106 | ); 107 | sourceTree = ""; 108 | }; 109 | 875B025D1CCDF1D500A12299 /* Products */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 875B025C1CCDF1D500A12299 /* WebViewShare.app */, 113 | 875B02751CCDF1D500A12299 /* WebViewShareTests.xctest */, 114 | 875B02801CCDF1D500A12299 /* WebViewShareUITests.xctest */, 115 | ); 116 | name = Products; 117 | sourceTree = ""; 118 | }; 119 | 875B025E1CCDF1D500A12299 /* WebViewShare */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 875B02951CCDFC6300A12299 /* WebViewMonitor */, 123 | 875B02621CCDF1D500A12299 /* AppDelegate.h */, 124 | 875B02631CCDF1D500A12299 /* AppDelegate.m */, 125 | 875B02921CCDFA2A00A12299 /* TableViewController.h */, 126 | 875B02931CCDFA2A00A12299 /* TableViewController.m */, 127 | 875B02961CCDFCA200A12299 /* TestUIWebView.h */, 128 | 875B02971CCDFCA200A12299 /* TestUIWebView.m */, 129 | 875B02991CCDFCBC00A12299 /* TestWKWebView.h */, 130 | 875B029A1CCDFCBC00A12299 /* TestWKWebView.m */, 131 | 875B02681CCDF1D500A12299 /* Main.storyboard */, 132 | 875B026B1CCDF1D500A12299 /* Assets.xcassets */, 133 | 875B026D1CCDF1D500A12299 /* LaunchScreen.storyboard */, 134 | 875B02701CCDF1D500A12299 /* Info.plist */, 135 | 875B025F1CCDF1D500A12299 /* Supporting Files */, 136 | ); 137 | path = WebViewShare; 138 | sourceTree = ""; 139 | }; 140 | 875B025F1CCDF1D500A12299 /* Supporting Files */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | 875B02601CCDF1D500A12299 /* main.m */, 144 | ); 145 | name = "Supporting Files"; 146 | sourceTree = ""; 147 | }; 148 | 875B02781CCDF1D500A12299 /* WebViewShareTests */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 875B02791CCDF1D500A12299 /* WebViewShareTests.m */, 152 | 875B027B1CCDF1D500A12299 /* Info.plist */, 153 | ); 154 | path = WebViewShareTests; 155 | sourceTree = ""; 156 | }; 157 | 875B02831CCDF1D500A12299 /* WebViewShareUITests */ = { 158 | isa = PBXGroup; 159 | children = ( 160 | 875B02841CCDF1D500A12299 /* WebViewShareUITests.m */, 161 | 875B02861CCDF1D500A12299 /* Info.plist */, 162 | ); 163 | path = WebViewShareUITests; 164 | sourceTree = ""; 165 | }; 166 | 875B02951CCDFC6300A12299 /* WebViewMonitor */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | 8743B1901CCF04CA001DC742 /* WebViewMonitor.framework */, 170 | 875B02A11CCE005F00A12299 /* WebViewTracker.h */, 171 | 875B02A21CCE005F00A12299 /* WebViewTracker.m */, 172 | 875B02A41CCE026D00A12299 /* WKWebViewTracker.h */, 173 | 875B02A51CCE026D00A12299 /* WKWebViewTracker.m */, 174 | 8743B1921CCF1711001DC742 /* MonitorURLProtocol.h */, 175 | 8743B1931CCF1711001DC742 /* MonitorURLProtocol.m */, 176 | ); 177 | name = WebViewMonitor; 178 | sourceTree = ""; 179 | }; 180 | /* End PBXGroup section */ 181 | 182 | /* Begin PBXNativeTarget section */ 183 | 875B025B1CCDF1D500A12299 /* WebViewShare */ = { 184 | isa = PBXNativeTarget; 185 | buildConfigurationList = 875B02891CCDF1D500A12299 /* Build configuration list for PBXNativeTarget "WebViewShare" */; 186 | buildPhases = ( 187 | 875B02581CCDF1D500A12299 /* Sources */, 188 | 875B02591CCDF1D500A12299 /* Frameworks */, 189 | 875B025A1CCDF1D500A12299 /* Resources */, 190 | ); 191 | buildRules = ( 192 | ); 193 | dependencies = ( 194 | ); 195 | name = WebViewShare; 196 | productName = WebViewShare; 197 | productReference = 875B025C1CCDF1D500A12299 /* WebViewShare.app */; 198 | productType = "com.apple.product-type.application"; 199 | }; 200 | 875B02741CCDF1D500A12299 /* WebViewShareTests */ = { 201 | isa = PBXNativeTarget; 202 | buildConfigurationList = 875B028C1CCDF1D500A12299 /* Build configuration list for PBXNativeTarget "WebViewShareTests" */; 203 | buildPhases = ( 204 | 875B02711CCDF1D500A12299 /* Sources */, 205 | 875B02721CCDF1D500A12299 /* Frameworks */, 206 | 875B02731CCDF1D500A12299 /* Resources */, 207 | ); 208 | buildRules = ( 209 | ); 210 | dependencies = ( 211 | 875B02771CCDF1D500A12299 /* PBXTargetDependency */, 212 | ); 213 | name = WebViewShareTests; 214 | productName = WebViewShareTests; 215 | productReference = 875B02751CCDF1D500A12299 /* WebViewShareTests.xctest */; 216 | productType = "com.apple.product-type.bundle.unit-test"; 217 | }; 218 | 875B027F1CCDF1D500A12299 /* WebViewShareUITests */ = { 219 | isa = PBXNativeTarget; 220 | buildConfigurationList = 875B028F1CCDF1D500A12299 /* Build configuration list for PBXNativeTarget "WebViewShareUITests" */; 221 | buildPhases = ( 222 | 875B027C1CCDF1D500A12299 /* Sources */, 223 | 875B027D1CCDF1D500A12299 /* Frameworks */, 224 | 875B027E1CCDF1D500A12299 /* Resources */, 225 | ); 226 | buildRules = ( 227 | ); 228 | dependencies = ( 229 | 875B02821CCDF1D500A12299 /* PBXTargetDependency */, 230 | ); 231 | name = WebViewShareUITests; 232 | productName = WebViewShareUITests; 233 | productReference = 875B02801CCDF1D500A12299 /* WebViewShareUITests.xctest */; 234 | productType = "com.apple.product-type.bundle.ui-testing"; 235 | }; 236 | /* End PBXNativeTarget section */ 237 | 238 | /* Begin PBXProject section */ 239 | 875B02541CCDF1D500A12299 /* Project object */ = { 240 | isa = PBXProject; 241 | attributes = { 242 | LastUpgradeCheck = 0730; 243 | ORGANIZATIONNAME = com.mobile; 244 | TargetAttributes = { 245 | 875B025B1CCDF1D500A12299 = { 246 | CreatedOnToolsVersion = 7.3; 247 | }; 248 | 875B02741CCDF1D500A12299 = { 249 | CreatedOnToolsVersion = 7.3; 250 | TestTargetID = 875B025B1CCDF1D500A12299; 251 | }; 252 | 875B027F1CCDF1D500A12299 = { 253 | CreatedOnToolsVersion = 7.3; 254 | TestTargetID = 875B025B1CCDF1D500A12299; 255 | }; 256 | }; 257 | }; 258 | buildConfigurationList = 875B02571CCDF1D500A12299 /* Build configuration list for PBXProject "WebViewShare" */; 259 | compatibilityVersion = "Xcode 3.2"; 260 | developmentRegion = English; 261 | hasScannedForEncodings = 0; 262 | knownRegions = ( 263 | en, 264 | Base, 265 | ); 266 | mainGroup = 875B02531CCDF1D400A12299; 267 | productRefGroup = 875B025D1CCDF1D500A12299 /* Products */; 268 | projectDirPath = ""; 269 | projectRoot = ""; 270 | targets = ( 271 | 875B025B1CCDF1D500A12299 /* WebViewShare */, 272 | 875B02741CCDF1D500A12299 /* WebViewShareTests */, 273 | 875B027F1CCDF1D500A12299 /* WebViewShareUITests */, 274 | ); 275 | }; 276 | /* End PBXProject section */ 277 | 278 | /* Begin PBXResourcesBuildPhase section */ 279 | 875B025A1CCDF1D500A12299 /* Resources */ = { 280 | isa = PBXResourcesBuildPhase; 281 | buildActionMask = 2147483647; 282 | files = ( 283 | 875B026F1CCDF1D500A12299 /* LaunchScreen.storyboard in Resources */, 284 | 875B026C1CCDF1D500A12299 /* Assets.xcassets in Resources */, 285 | 875B026A1CCDF1D500A12299 /* Main.storyboard in Resources */, 286 | ); 287 | runOnlyForDeploymentPostprocessing = 0; 288 | }; 289 | 875B02731CCDF1D500A12299 /* Resources */ = { 290 | isa = PBXResourcesBuildPhase; 291 | buildActionMask = 2147483647; 292 | files = ( 293 | ); 294 | runOnlyForDeploymentPostprocessing = 0; 295 | }; 296 | 875B027E1CCDF1D500A12299 /* Resources */ = { 297 | isa = PBXResourcesBuildPhase; 298 | buildActionMask = 2147483647; 299 | files = ( 300 | ); 301 | runOnlyForDeploymentPostprocessing = 0; 302 | }; 303 | /* End PBXResourcesBuildPhase section */ 304 | 305 | /* Begin PBXSourcesBuildPhase section */ 306 | 875B02581CCDF1D500A12299 /* Sources */ = { 307 | isa = PBXSourcesBuildPhase; 308 | buildActionMask = 2147483647; 309 | files = ( 310 | 875B02641CCDF1D500A12299 /* AppDelegate.m in Sources */, 311 | 875B02981CCDFCA200A12299 /* TestUIWebView.m in Sources */, 312 | 875B02611CCDF1D500A12299 /* main.m in Sources */, 313 | 875B02A61CCE026D00A12299 /* WKWebViewTracker.m in Sources */, 314 | 875B02941CCDFA2A00A12299 /* TableViewController.m in Sources */, 315 | 875B02A31CCE005F00A12299 /* WebViewTracker.m in Sources */, 316 | 8743B1941CCF1711001DC742 /* MonitorURLProtocol.m in Sources */, 317 | 875B029B1CCDFCBC00A12299 /* TestWKWebView.m in Sources */, 318 | ); 319 | runOnlyForDeploymentPostprocessing = 0; 320 | }; 321 | 875B02711CCDF1D500A12299 /* Sources */ = { 322 | isa = PBXSourcesBuildPhase; 323 | buildActionMask = 2147483647; 324 | files = ( 325 | 875B027A1CCDF1D500A12299 /* WebViewShareTests.m in Sources */, 326 | ); 327 | runOnlyForDeploymentPostprocessing = 0; 328 | }; 329 | 875B027C1CCDF1D500A12299 /* Sources */ = { 330 | isa = PBXSourcesBuildPhase; 331 | buildActionMask = 2147483647; 332 | files = ( 333 | 875B02851CCDF1D500A12299 /* WebViewShareUITests.m in Sources */, 334 | ); 335 | runOnlyForDeploymentPostprocessing = 0; 336 | }; 337 | /* End PBXSourcesBuildPhase section */ 338 | 339 | /* Begin PBXTargetDependency section */ 340 | 875B02771CCDF1D500A12299 /* PBXTargetDependency */ = { 341 | isa = PBXTargetDependency; 342 | target = 875B025B1CCDF1D500A12299 /* WebViewShare */; 343 | targetProxy = 875B02761CCDF1D500A12299 /* PBXContainerItemProxy */; 344 | }; 345 | 875B02821CCDF1D500A12299 /* PBXTargetDependency */ = { 346 | isa = PBXTargetDependency; 347 | target = 875B025B1CCDF1D500A12299 /* WebViewShare */; 348 | targetProxy = 875B02811CCDF1D500A12299 /* PBXContainerItemProxy */; 349 | }; 350 | /* End PBXTargetDependency section */ 351 | 352 | /* Begin PBXVariantGroup section */ 353 | 875B02681CCDF1D500A12299 /* Main.storyboard */ = { 354 | isa = PBXVariantGroup; 355 | children = ( 356 | 875B02691CCDF1D500A12299 /* Base */, 357 | ); 358 | name = Main.storyboard; 359 | sourceTree = ""; 360 | }; 361 | 875B026D1CCDF1D500A12299 /* LaunchScreen.storyboard */ = { 362 | isa = PBXVariantGroup; 363 | children = ( 364 | 875B026E1CCDF1D500A12299 /* Base */, 365 | ); 366 | name = LaunchScreen.storyboard; 367 | sourceTree = ""; 368 | }; 369 | /* End PBXVariantGroup section */ 370 | 371 | /* Begin XCBuildConfiguration section */ 372 | 875B02871CCDF1D500A12299 /* Debug */ = { 373 | isa = XCBuildConfiguration; 374 | buildSettings = { 375 | ALWAYS_SEARCH_USER_PATHS = NO; 376 | CLANG_ANALYZER_NONNULL = YES; 377 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 378 | CLANG_CXX_LIBRARY = "libc++"; 379 | CLANG_ENABLE_MODULES = YES; 380 | CLANG_ENABLE_OBJC_ARC = YES; 381 | CLANG_WARN_BOOL_CONVERSION = YES; 382 | CLANG_WARN_CONSTANT_CONVERSION = YES; 383 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 384 | CLANG_WARN_EMPTY_BODY = YES; 385 | CLANG_WARN_ENUM_CONVERSION = YES; 386 | CLANG_WARN_INT_CONVERSION = YES; 387 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 388 | CLANG_WARN_UNREACHABLE_CODE = YES; 389 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 390 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 391 | COPY_PHASE_STRIP = NO; 392 | DEBUG_INFORMATION_FORMAT = dwarf; 393 | ENABLE_STRICT_OBJC_MSGSEND = YES; 394 | ENABLE_TESTABILITY = YES; 395 | GCC_C_LANGUAGE_STANDARD = gnu99; 396 | GCC_DYNAMIC_NO_PIC = NO; 397 | GCC_NO_COMMON_BLOCKS = YES; 398 | GCC_OPTIMIZATION_LEVEL = 0; 399 | GCC_PREPROCESSOR_DEFINITIONS = ( 400 | "DEBUG=1", 401 | "$(inherited)", 402 | ); 403 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 404 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 405 | GCC_WARN_UNDECLARED_SELECTOR = YES; 406 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 407 | GCC_WARN_UNUSED_FUNCTION = YES; 408 | GCC_WARN_UNUSED_VARIABLE = YES; 409 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 410 | MTL_ENABLE_DEBUG_INFO = YES; 411 | ONLY_ACTIVE_ARCH = YES; 412 | SDKROOT = iphoneos; 413 | TARGETED_DEVICE_FAMILY = "1,2"; 414 | }; 415 | name = Debug; 416 | }; 417 | 875B02881CCDF1D500A12299 /* Release */ = { 418 | isa = XCBuildConfiguration; 419 | buildSettings = { 420 | ALWAYS_SEARCH_USER_PATHS = NO; 421 | CLANG_ANALYZER_NONNULL = YES; 422 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 423 | CLANG_CXX_LIBRARY = "libc++"; 424 | CLANG_ENABLE_MODULES = YES; 425 | CLANG_ENABLE_OBJC_ARC = YES; 426 | CLANG_WARN_BOOL_CONVERSION = YES; 427 | CLANG_WARN_CONSTANT_CONVERSION = YES; 428 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 429 | CLANG_WARN_EMPTY_BODY = YES; 430 | CLANG_WARN_ENUM_CONVERSION = YES; 431 | CLANG_WARN_INT_CONVERSION = YES; 432 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 433 | CLANG_WARN_UNREACHABLE_CODE = YES; 434 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 435 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 436 | COPY_PHASE_STRIP = NO; 437 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 438 | ENABLE_NS_ASSERTIONS = NO; 439 | ENABLE_STRICT_OBJC_MSGSEND = YES; 440 | GCC_C_LANGUAGE_STANDARD = gnu99; 441 | GCC_NO_COMMON_BLOCKS = YES; 442 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 443 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 444 | GCC_WARN_UNDECLARED_SELECTOR = YES; 445 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 446 | GCC_WARN_UNUSED_FUNCTION = YES; 447 | GCC_WARN_UNUSED_VARIABLE = YES; 448 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 449 | MTL_ENABLE_DEBUG_INFO = NO; 450 | SDKROOT = iphoneos; 451 | TARGETED_DEVICE_FAMILY = "1,2"; 452 | VALIDATE_PRODUCT = YES; 453 | }; 454 | name = Release; 455 | }; 456 | 875B028A1CCDF1D500A12299 /* Debug */ = { 457 | isa = XCBuildConfiguration; 458 | buildSettings = { 459 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 460 | FRAMEWORK_SEARCH_PATHS = ( 461 | "$(inherited)", 462 | "$(PROJECT_DIR)/WebViewShare", 463 | ); 464 | GCC_GENERATE_DEBUGGING_SYMBOLS = YES; 465 | INFOPLIST_FILE = WebViewShare/Info.plist; 466 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 467 | PRODUCT_BUNDLE_IDENTIFIER = com.CWSA.Share.WebViewShare; 468 | PRODUCT_NAME = "$(TARGET_NAME)"; 469 | }; 470 | name = Debug; 471 | }; 472 | 875B028B1CCDF1D500A12299 /* Release */ = { 473 | isa = XCBuildConfiguration; 474 | buildSettings = { 475 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 476 | FRAMEWORK_SEARCH_PATHS = ( 477 | "$(inherited)", 478 | "$(PROJECT_DIR)/WebViewShare", 479 | ); 480 | GCC_GENERATE_DEBUGGING_SYMBOLS = YES; 481 | INFOPLIST_FILE = WebViewShare/Info.plist; 482 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 483 | PRODUCT_BUNDLE_IDENTIFIER = com.CWSA.Share.WebViewShare; 484 | PRODUCT_NAME = "$(TARGET_NAME)"; 485 | }; 486 | name = Release; 487 | }; 488 | 875B028D1CCDF1D500A12299 /* Debug */ = { 489 | isa = XCBuildConfiguration; 490 | buildSettings = { 491 | BUNDLE_LOADER = "$(TEST_HOST)"; 492 | INFOPLIST_FILE = WebViewShareTests/Info.plist; 493 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 494 | PRODUCT_BUNDLE_IDENTIFIER = com.CWSA.Share.WebViewShareTests; 495 | PRODUCT_NAME = "$(TARGET_NAME)"; 496 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WebViewShare.app/WebViewShare"; 497 | }; 498 | name = Debug; 499 | }; 500 | 875B028E1CCDF1D500A12299 /* Release */ = { 501 | isa = XCBuildConfiguration; 502 | buildSettings = { 503 | BUNDLE_LOADER = "$(TEST_HOST)"; 504 | INFOPLIST_FILE = WebViewShareTests/Info.plist; 505 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 506 | PRODUCT_BUNDLE_IDENTIFIER = com.CWSA.Share.WebViewShareTests; 507 | PRODUCT_NAME = "$(TARGET_NAME)"; 508 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WebViewShare.app/WebViewShare"; 509 | }; 510 | name = Release; 511 | }; 512 | 875B02901CCDF1D500A12299 /* Debug */ = { 513 | isa = XCBuildConfiguration; 514 | buildSettings = { 515 | INFOPLIST_FILE = WebViewShareUITests/Info.plist; 516 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 517 | PRODUCT_BUNDLE_IDENTIFIER = com.CWSA.Share.WebViewShareUITests; 518 | PRODUCT_NAME = "$(TARGET_NAME)"; 519 | TEST_TARGET_NAME = WebViewShare; 520 | }; 521 | name = Debug; 522 | }; 523 | 875B02911CCDF1D500A12299 /* Release */ = { 524 | isa = XCBuildConfiguration; 525 | buildSettings = { 526 | INFOPLIST_FILE = WebViewShareUITests/Info.plist; 527 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 528 | PRODUCT_BUNDLE_IDENTIFIER = com.CWSA.Share.WebViewShareUITests; 529 | PRODUCT_NAME = "$(TARGET_NAME)"; 530 | TEST_TARGET_NAME = WebViewShare; 531 | }; 532 | name = Release; 533 | }; 534 | /* End XCBuildConfiguration section */ 535 | 536 | /* Begin XCConfigurationList section */ 537 | 875B02571CCDF1D500A12299 /* Build configuration list for PBXProject "WebViewShare" */ = { 538 | isa = XCConfigurationList; 539 | buildConfigurations = ( 540 | 875B02871CCDF1D500A12299 /* Debug */, 541 | 875B02881CCDF1D500A12299 /* Release */, 542 | ); 543 | defaultConfigurationIsVisible = 0; 544 | defaultConfigurationName = Release; 545 | }; 546 | 875B02891CCDF1D500A12299 /* Build configuration list for PBXNativeTarget "WebViewShare" */ = { 547 | isa = XCConfigurationList; 548 | buildConfigurations = ( 549 | 875B028A1CCDF1D500A12299 /* Debug */, 550 | 875B028B1CCDF1D500A12299 /* Release */, 551 | ); 552 | defaultConfigurationIsVisible = 0; 553 | defaultConfigurationName = Release; 554 | }; 555 | 875B028C1CCDF1D500A12299 /* Build configuration list for PBXNativeTarget "WebViewShareTests" */ = { 556 | isa = XCConfigurationList; 557 | buildConfigurations = ( 558 | 875B028D1CCDF1D500A12299 /* Debug */, 559 | 875B028E1CCDF1D500A12299 /* Release */, 560 | ); 561 | defaultConfigurationIsVisible = 0; 562 | defaultConfigurationName = Release; 563 | }; 564 | 875B028F1CCDF1D500A12299 /* Build configuration list for PBXNativeTarget "WebViewShareUITests" */ = { 565 | isa = XCConfigurationList; 566 | buildConfigurations = ( 567 | 875B02901CCDF1D500A12299 /* Debug */, 568 | 875B02911CCDF1D500A12299 /* Release */, 569 | ); 570 | defaultConfigurationIsVisible = 0; 571 | defaultConfigurationName = Release; 572 | }; 573 | /* End XCConfigurationList section */ 574 | }; 575 | rootObject = 875B02541CCDF1D500A12299 /* Project object */; 576 | } 577 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare.xcodeproj/project.xcworkspace/xcuserdata/Cyan.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LonylyMark/WebViewMonitor/946cb1e349e75fe771c9c725a690e9e2c157f149/WebViewShare/WebViewShare.xcodeproj/project.xcworkspace/xcuserdata/Cyan.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /WebViewShare/WebViewShare.xcodeproj/xcuserdata/Cyan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare.xcodeproj/xcuserdata/Cyan.xcuserdatad/xcschemes/WebViewShare.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 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare.xcodeproj/xcuserdata/Cyan.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | WebViewShare.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 875B025B1CCDF1D500A12299 16 | 17 | primary 18 | 19 | 20 | 875B02741CCDF1D500A12299 21 | 22 | primary 23 | 24 | 25 | 875B027F1CCDF1D500A12299 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // WebViewShare 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // WebViewShare 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "TableViewController.h" 11 | #import "WebViewTracker.h" 12 | 13 | #import "MonitorURLProtocol.h" 14 | @interface AppDelegate () 15 | 16 | @end 17 | 18 | @implementation AppDelegate 19 | 20 | 21 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 22 | 23 | [NSURLProtocol registerClass:[MonitorURLProtocol class]]; 24 | 25 | _window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 26 | _window.backgroundColor = [UIColor whiteColor]; 27 | [_window makeKeyAndVisible]; 28 | 29 | TableViewController *vc = [[TableViewController alloc] init]; 30 | UINavigationController *naVC = [[UINavigationController alloc] initWithRootViewController:vc]; 31 | _window.rootViewController = naVC; 32 | 33 | return YES; 34 | } 35 | 36 | - (void)applicationWillResignActive:(UIApplication *)application { 37 | // 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. 38 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 39 | } 40 | 41 | - (void)applicationDidEnterBackground:(UIApplication *)application { 42 | // 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. 43 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 44 | } 45 | 46 | - (void)applicationWillEnterForeground:(UIApplication *)application { 47 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 48 | } 49 | 50 | - (void)applicationDidBecomeActive:(UIApplication *)application { 51 | // 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. 52 | } 53 | 54 | - (void)applicationWillTerminate:(UIApplication *)application { 55 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/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 | 27 | 28 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/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 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | NSAppTransportSecurity 40 | 41 | NSAllowsArbitraryLoads 42 | 43 | 44 | UISupportedInterfaceOrientations~ipad 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationPortraitUpsideDown 48 | UIInterfaceOrientationLandscapeLeft 49 | UIInterfaceOrientationLandscapeRight 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/MonitorURLProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // MonitorURLProtocol.h 3 | // WebViewShare 4 | // 5 | // Created by cyan color on 16/4/26. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MonitorURLProtocol : NSURLProtocol 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/MonitorURLProtocol.m: -------------------------------------------------------------------------------- 1 | // 2 | // MonitorURLProtocol.m 3 | // WebViewShare 4 | // 5 | // Created by cyan color on 16/4/26. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import "MonitorURLProtocol.h" 10 | #import 11 | //调试输出打印的日志 1是输出 0 不输出 12 | #define WebView_DEBUG 0 13 | #if WebView_DEBUG 14 | #define LOG(...) NSLog(__VA_ARGS__); 15 | #else 16 | #define LOG(...); 17 | #endif 18 | 19 | @interface MonitorURLProtocol() 20 | @property (nonatomic,strong)NSURLConnection *connection; 21 | @end 22 | @implementation MonitorURLProtocol 23 | static NSString *HandledKey = @"WebViewMonitor"; 24 | static NSOperationQueue* _queue; 25 | 26 | +(void)initialize { 27 | _queue = [NSOperationQueue new]; 28 | [_queue setMaxConcurrentOperationCount:20]; 29 | } 30 | #pragma mark -- NSURLProtocol 31 | + (BOOL)canInitWithRequest:(NSURLRequest *)request { 32 | 33 | if ([NSURLProtocol propertyForKey:HandledKey inRequest:request] != nil) { 34 | return NO; 35 | } 36 | 37 | return YES; 38 | } 39 | 40 | -(instancetype)initWithRequest:(NSURLRequest *)request 41 | cachedResponse:(NSCachedURLResponse *)cachedResponse 42 | client:(id)client { 43 | 44 | return [super initWithRequest:request 45 | cachedResponse:cachedResponse 46 | client:client]; 47 | } 48 | 49 | 50 | 51 | + (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a 52 | toRequest:(NSURLRequest *)b 53 | { 54 | return [super requestIsCacheEquivalent:a toRequest:b]; 55 | } 56 | 57 | 58 | + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request { 59 | return request; 60 | } 61 | 62 | - (void)startLoading { 63 | // init property variable 64 | 65 | 66 | 67 | NSMutableURLRequest *newRequest = [self.request mutableCopy]; 68 | 69 | [NSURLProtocol setProperty:@YES forKey:HandledKey inRequest:newRequest]; 70 | 71 | _connection = [[NSURLConnection alloc] initWithRequest:newRequest 72 | delegate:self 73 | startImmediately:NO]; 74 | // comment out for sure stalling 75 | [_connection setDelegateQueue:_queue]; 76 | [_connection start]; 77 | 78 | 79 | } 80 | 81 | - (void)stopLoading 82 | { 83 | [self.connection cancel]; 84 | self.connection = nil; 85 | } 86 | 87 | #pragma mark -- NSURLProtocolClient 88 | 89 | - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { 90 | 91 | [self.client URLProtocol:self didFailWithError:error]; 92 | self.connection = nil; 93 | 94 | 95 | } 96 | 97 | - (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response{ 98 | if (response != nil) 99 | { 100 | NSMutableURLRequest *redirectableRequest = [request mutableCopy]; 101 | 102 | [self.client URLProtocol:self wasRedirectedToRequest:redirectableRequest redirectResponse:response]; 103 | return redirectableRequest; 104 | } 105 | return request; 106 | } 107 | 108 | - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { 109 | 110 | 111 | [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; 112 | } 113 | 114 | - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 115 | { 116 | 117 | NSString *htmlStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 118 | //自由关闭日志输出 119 | LOG(@"html=%@",htmlStr); 120 | if (htmlStr) { 121 | NSMutableString *multiStr = [NSMutableString stringWithString:htmlStr]; 122 | NSRange range = [multiStr rangeOfString:@""];//\n",jsStr]; 128 | [multiStr insertString:injectJSStr atIndex:(range.location + range.length)]; 129 | NSData *mutilData = [multiStr dataUsingEncoding:NSUTF8StringEncoding]; 130 | [self.client URLProtocol:self didLoadData:mutilData]; 131 | 132 | 133 | }else{ 134 | 135 | [self.client URLProtocol:self didLoadData:data]; 136 | } 137 | }else{ 138 | 139 | [self.client URLProtocol:self didLoadData:data]; 140 | } 141 | 142 | } 143 | 144 | 145 | - (void)connectionDidFinishLoading:(NSURLConnection *)connection { 146 | 147 | [self.client URLProtocolDidFinishLoading:self]; 148 | 149 | self.connection = nil; 150 | 151 | 152 | } 153 | 154 | 155 | 156 | @end 157 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/TableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewController.h 3 | // WebViewShare 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TableViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/TableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewController.m 3 | // WebViewShare 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import "TableViewController.h" 10 | #import "TestUIWebView.h" 11 | #import "TestWKWebView.h" 12 | 13 | @interface TableViewController () 14 | @property (nonatomic,strong)UITableView *tableView; 15 | @property (nonatomic,strong)NSArray *dataSource; 16 | @end 17 | 18 | @implementation TableViewController 19 | 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | 23 | _dataSource = @[@"UIWebView",@"WKWebView"]; 24 | _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height-64) style:UITableViewStylePlain]; 25 | _tableView.delegate = self; 26 | _tableView.dataSource = self; 27 | _tableView.backgroundColor = [UIColor clearColor]; 28 | [self.view addSubview:_tableView]; 29 | 30 | _tableView.tableFooterView = [[UIView alloc] init]; 31 | } 32 | #pragma mark datasource 33 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; 34 | { 35 | return 1; 36 | } 37 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; 38 | { 39 | return 2; 40 | } 41 | 42 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; 43 | { 44 | static NSString *iden = @"cell"; 45 | UITableViewCell *tableViewCell = [tableView dequeueReusableCellWithIdentifier:iden]; 46 | if (tableViewCell == nil) { 47 | tableViewCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:iden]; 48 | } 49 | tableViewCell.textLabel.text = _dataSource[indexPath.row]; 50 | 51 | return tableViewCell; 52 | } 53 | #pragma mark delegate 54 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; 55 | { 56 | switch (indexPath.row) { 57 | case 0: 58 | { 59 | TestUIWebView *testUI = [[TestUIWebView alloc] init]; 60 | [self.navigationController pushViewController:testUI animated:YES]; 61 | } 62 | break; 63 | case 1: 64 | { 65 | TestWKWebView *testWK = [[TestWKWebView alloc] init]; 66 | [self.navigationController pushViewController:testWK animated:YES]; 67 | } 68 | break; 69 | default: 70 | break; 71 | } 72 | } 73 | 74 | 75 | - (void)didReceiveMemoryWarning { 76 | [super didReceiveMemoryWarning]; 77 | // Dispose of any resources that can be recreated. 78 | } 79 | 80 | /* 81 | #pragma mark - Navigation 82 | 83 | // In a storyboard-based application, you will often want to do a little preparation before navigation 84 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 85 | // Get the new view controller using [segue destinationViewController]. 86 | // Pass the selected object to the new view controller. 87 | } 88 | */ 89 | 90 | @end 91 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/TestUIWebView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TestUIWebView.h 3 | // WebViewShare 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TestUIWebView : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/TestUIWebView.m: -------------------------------------------------------------------------------- 1 | // 2 | // TestUIWebView.m 3 | // WebViewShare 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import "TestUIWebView.h" 10 | #import "WebViewTracker.h" 11 | #import 12 | @interface TestUIWebView () 13 | 14 | @end 15 | 16 | @implementation TestUIWebView 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | UIWebView *webView = [[UIWebView alloc] initWithFrame:self.view.bounds]; 21 | NSString *str = @"http://www.baidu.com"; 22 | NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:str]]; 23 | [webView loadRequest:request]; 24 | webView.delegate = self; 25 | [self.view addSubview:webView]; 26 | 27 | 28 | } 29 | - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType; 30 | { 31 | [WebViewTracker webView:webView withUrl:request.URL]; 32 | return YES; 33 | } 34 | - (void)webViewDidStartLoad:(UIWebView *)webView; 35 | { 36 | 37 | } 38 | - (void)webViewDidFinishLoad:(UIWebView *)webView; 39 | { 40 | //使用NSURLProtocol注入获取ajax代码,因为ajax必须头部注入,不然会丢失数据,而行为和性能数据在头部注入的话也会丢失数据,所以结合着用 41 | 42 | NSString *jsStr = WebViewOnclickAndResource_js(); 43 | jsStr = [jsStr substringWithRange:NSMakeRange(2, jsStr.length-3)]; 44 | [webView stringByEvaluatingJavaScriptFromString:jsStr]; 45 | [webView stringByEvaluatingJavaScriptFromString:@"CloudwiseAddEvent()"]; 46 | [webView stringByEvaluatingJavaScriptFromString:@"cloudwiseStartPageMonitor()"]; 47 | 48 | 49 | } 50 | - (void)webView:(UIWebView *)webView didFailLoadWithError:(nullable NSError *)error; 51 | { 52 | 53 | } 54 | - (void)didReceiveMemoryWarning { 55 | [super didReceiveMemoryWarning]; 56 | // Dispose of any resources that can be recreated. 57 | } 58 | 59 | /* 60 | #pragma mark - Navigation 61 | 62 | // In a storyboard-based application, you will often want to do a little preparation before navigation 63 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 64 | // Get the new view controller using [segue destinationViewController]. 65 | // Pass the selected object to the new view controller. 66 | } 67 | */ 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/TestWKWebView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TestWKWebView.h 3 | // WebViewShare 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TestWKWebView : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/TestWKWebView.m: -------------------------------------------------------------------------------- 1 | // 2 | // TestWKWebView.m 3 | // WebViewShare 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import "TestWKWebView.h" 10 | #import 11 | #import 12 | #import "WKWebViewTracker.h" 13 | @interface TestWKWebView () 14 | @property (nonatomic,strong)WKWebView *wkWebView; 15 | @end 16 | 17 | @implementation TestWKWebView 18 | 19 | - (void)viewDidLoad { 20 | [super viewDidLoad]; 21 | 22 | _wkWebView = [[WKWebView alloc] initWithFrame:self.view.bounds]; 23 | _wkWebView.navigationDelegate = self; 24 | NSString *str = @"http://www.baidu.com"; 25 | [_wkWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:str]]]; 26 | 27 | [self.view addSubview:_wkWebView]; 28 | } 29 | #pragma mark - WKNavigationDelegate 30 | - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler 31 | { 32 | NSLog(@"decidePolicyForNavigationAction"); 33 | 34 | [WKWebViewTracker wkWebView:webView withUrl:navigationAction.request.URL]; 35 | // NSLog(@"url=%@",navigationAction.request.URL); 36 | decisionHandler(WKNavigationActionPolicyAllow); 37 | 38 | } 39 | 40 | - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation { 41 | NSLog(@"didStartProvisionalNavigation"); 42 | } 43 | 44 | - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { 45 | 46 | NSString *jsStr = WKWebViewJavaScript_js(); 47 | jsStr = [jsStr substringWithRange:NSMakeRange(2, jsStr.length-3)]; 48 | [webView evaluateJavaScript:jsStr completionHandler:nil]; 49 | [webView evaluateJavaScript:@"CloudwiseAddEvent()" completionHandler:^(id object, NSError * _Nullable error) { 50 | 51 | }]; 52 | [webView evaluateJavaScript:@"cloudwiseStartPageMonitor()" completionHandler:nil]; 53 | [webView evaluateJavaScript:@"cloudwisePreMonitor()" completionHandler:nil]; 54 | NSLog(@"didFinishNavigation"); 55 | } 56 | 57 | - (void)didReceiveMemoryWarning { 58 | [super didReceiveMemoryWarning]; 59 | // Dispose of any resources that can be recreated. 60 | } 61 | 62 | /* 63 | #pragma mark - Navigation 64 | 65 | // In a storyboard-based application, you will often want to do a little preparation before navigation 66 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 67 | // Get the new view controller using [segue destinationViewController]. 68 | // Pass the selected object to the new view controller. 69 | } 70 | */ 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // WebViewShare 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // WebViewShare 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @interface ViewController () 12 | @property (nonatomic,strong)UITableView *tableView; 13 | 14 | @end 15 | 16 | @implementation ViewController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | 21 | _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 64, self.view.frame.size.width, self.view.frame.size.height-64) style:UITableViewStylePlain]; 22 | _tableView.delegate = self; 23 | _tableView.dataSource = self; 24 | _tableView.backgroundColor = [UIColor clearColor]; 25 | [self.view addSubview:_tableView]; 26 | } 27 | #pragma mark datasource 28 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; 29 | { 30 | return 1; 31 | } 32 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; 33 | { 34 | return 10; 35 | } 36 | 37 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; 38 | { 39 | static NSString *cell = @"cell"; 40 | UITableViewCell *tableViewCell = [tableView dequeueReusableCellWithIdentifier:cell]; 41 | if (cell == nil) { 42 | tableViewCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cell]; 43 | } 44 | tableViewCell.textLabel.text = @"123"; 45 | 46 | return tableViewCell; 47 | } 48 | #pragma mark delegate 49 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; 50 | { 51 | 52 | } 53 | - (void)didReceiveMemoryWarning { 54 | [super didReceiveMemoryWarning]; 55 | 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/WKWebViewTracker.h: -------------------------------------------------------------------------------- 1 | // 2 | // WKWebViewTracker.h 3 | // WebViewShare 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | typedef void(^ WKWebViewTrackerMonitor)(NSDictionary *payload); 12 | typedef void (^ WKWebViewTrackerAsyncMonitor)(WKWebView *webView, NSDictionary *payload); 13 | @interface WKWebViewTracker : NSObject 14 | + (id)shareInstance; 15 | + (BOOL)wkWebView:(WKWebView *)webView withUrl:(NSURL*)url; 16 | @end 17 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/WKWebViewTracker.m: -------------------------------------------------------------------------------- 1 | // 2 | // WKWebViewTracker.m 3 | // WebViewShare 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import "WKWebViewTracker.h" 10 | #import 11 | 12 | @interface WKWebViewTracker() 13 | @property (strong, nonatomic) NSMutableDictionary *listeners; 14 | @end 15 | @implementation WKWebViewTracker 16 | + (id)shareInstance; 17 | { 18 | static dispatch_once_t once; 19 | static WKWebViewTracker *instance; 20 | dispatch_once(&once, ^{ 21 | instance = [[self alloc] init]; 22 | instance.listeners = [[NSMutableDictionary alloc] init]; 23 | }); 24 | return instance; 25 | } 26 | void WKWebViewSwizzle(Class c, SEL orig, SEL newS) { 27 | 28 | Method origMethod = class_getInstanceMethod(c, orig); 29 | Method newMethod = class_getInstanceMethod(c, newS); 30 | if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) { 31 | class_replaceMethod(c, newS, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); 32 | } else { 33 | method_exchangeImplementations(origMethod, newMethod); 34 | } 35 | } 36 | 37 | + (void)sendType:(NSString *)type perform:(WKWebViewTrackerMonitor)monitor 38 | { 39 | void (^ extend)(WKWebView *webView,NSDictionary *payload) = ^(WKWebView *webView,NSDictionary *payload){ 40 | monitor(payload); 41 | 42 | }; 43 | [self sendType:type addType:extend]; 44 | } 45 | + (void)sendType:(NSString *)type addType:(WKWebViewTrackerAsyncMonitor)monitor 46 | { 47 | WKWebViewTracker *instance = [WKWebViewTracker shareInstance]; 48 | 49 | NSDictionary *listeners = [instance listeners]; 50 | 51 | NSMutableArray *listenerList = [listeners objectForKey:type]; 52 | 53 | if (listenerList == nil) { 54 | listenerList = [[NSMutableArray alloc] init]; 55 | 56 | [instance.listeners setValue:listenerList forKey:type]; 57 | [listenerList addObject:monitor]; 58 | } 59 | } 60 | 61 | + (BOOL)wkWebView:(WKWebView*)webView withUrl:(NSURL*)url 62 | { 63 | if ([[url scheme] isEqualToString:@"cloudwise-agent"]) { 64 | 65 | NSString *eventType = [url host]; 66 | NSString *query = [url query]; 67 | NSString *jsonString = [query stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 68 | 69 | NSError *error; 70 | NSDictionary *JSON = [NSJSONSerialization 71 | JSONObjectWithData: [jsonString dataUsingEncoding:NSUTF8StringEncoding] 72 | options: NSJSONReadingAllowFragments 73 | error: &error]; 74 | 75 | if ([eventType isEqualToString:@"timing"]) 76 | { 77 | 78 | [[self shareInstance] triggerEventFromWebView:webView withData:JSON]; 79 | 80 | }else if ([eventType isEqualToString:@"ajax"]) 81 | { 82 | 83 | [[self shareInstance] triggerEventFromWebView:webView withData:JSON]; 84 | } 85 | 86 | return NO; 87 | } 88 | 89 | 90 | if ([[url scheme] isEqualToString:@"cloudwise"] ) 91 | { 92 | NSString *eventType = [url host]; 93 | // NSString *messageId = [[url path] substringFromIndex:1]; 94 | NSString *query = [url query]; 95 | NSString *jsonString = [query stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 96 | 97 | NSError *error; 98 | NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData: [jsonString dataUsingEncoding:NSUTF8StringEncoding] 99 | options: NSJSONReadingMutableContainers 100 | error: &error]; 101 | 102 | if ([eventType isEqualToString:@"event"]) { 103 | [[self shareInstance] triggerEventFromWebView:webView withData:JSON]; 104 | } 105 | 106 | return NO; 107 | } 108 | 109 | return YES; 110 | } 111 | 112 | - (void)triggerEventFromWebView:(WKWebView*)webView withData:(NSDictionary*)envelope 113 | { 114 | 115 | NSDictionary *listeners = [[WKWebViewTracker shareInstance] listeners]; 116 | 117 | NSString *type = [envelope objectForKey:@"type"]; 118 | 119 | NSDictionary *payload = [envelope objectForKey:@"payload"]; 120 | NSArray *listenerList = (NSArray*)[listeners objectForKey:type]; 121 | 122 | for (WKWebViewTrackerAsyncMonitor handler in listenerList) 123 | { 124 | handler(webView, payload); 125 | } 126 | 127 | } 128 | @end 129 | 130 | @interface WKWebView (monitor) 131 | 132 | 133 | @end 134 | @implementation WKWebView (monitor) 135 | 136 | +(void)load 137 | { 138 | static dispatch_once_t onceToken; 139 | dispatch_once(&onceToken, ^{ 140 | 141 | Class webViewCls = [WKWebView class]; 142 | WKWebViewSwizzle(webViewCls, @selector(loadRequest:), sel_registerName("WKwebViewMonitor_loadRequest:")); 143 | WKWebViewSwizzle(webViewCls, @selector(loadFileURL:allowingReadAccessToURL:), sel_registerName("WKwebViewMonitor_loadFile:allowingReadAccessToURL:")); 144 | WKWebViewSwizzle(webViewCls, @selector(loadHTMLString:baseURL:), sel_registerName("WKwebViewMonitor_loadHTMLString:baseURL:")); 145 | WKWebViewSwizzle(webViewCls, @selector(loadData:MIMEType:characterEncodingName:baseURL:), sel_registerName("WKwebViewMonitor_loadData:MIMEType:characterEncodingName:baseURL:")); 146 | }); 147 | 148 | } 149 | - (WKNavigation *)WKwebViewMonitor_loadRequest:(NSURLRequest *)request 150 | { 151 | 152 | wkWebViewMonitor(self); 153 | 154 | 155 | return [self WKwebViewMonitor_loadRequest:request]; 156 | 157 | } 158 | - (WKNavigation *)WKwebViewMonitor_loadFile:(NSURL *)url allowingReadAccessToURL:(NSURL *)readAccessToURL 159 | { 160 | 161 | wkWebViewMonitor(self); 162 | 163 | return [self WKwebViewMonitor_loadFile:url allowingReadAccessToURL:readAccessToURL]; 164 | } 165 | 166 | - (WKNavigation *)WKwebViewMonitor_loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL 167 | { 168 | 169 | wkWebViewMonitor(self); 170 | 171 | return [self WKwebViewMonitor_loadHTMLString:string baseURL:baseURL]; 172 | } 173 | - (WKNavigation *)WKwebViewMonitor_loadData:(NSData *)data MIMEType:(NSString *)type characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL 174 | { 175 | 176 | wkWebViewMonitor(self); 177 | 178 | return [self WKwebViewMonitor_loadData:data MIMEType:type characterEncodingName:characterEncodingName baseURL:baseURL]; 179 | } 180 | 181 | static void wkWebViewMonitor(WKWebView *wk_self) 182 | { 183 | [WKWebViewTracker sendType:@"onclick" perform:^(NSDictionary *payload) { 184 | NSLog(@"click-wk=%@",payload); 185 | }]; 186 | 187 | [WKWebViewTracker sendType:@"cloudwise_monitor" perform:^(NSDictionary *payload) { 188 | NSLog(@"timing=wk=%@",payload); 189 | }]; 190 | 191 | [WKWebViewTracker sendType:@"cloudwise_monitor_ajax" perform:^(NSDictionary *payload) { 192 | NSLog(@"ajax-wk=%@",payload); 193 | }]; 194 | } 195 | 196 | @end -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/WebViewMonitor.framework/Headers/WebViewJavaScript_js.h: -------------------------------------------------------------------------------- 1 | // 2 | // WebViewJavaScript_js.h 3 | // WebViewMonitor 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | //点击事件和资源时序数据 13 | NSString * WebViewOnclickAndResource_js(); 14 | //ajax请求和js错误 15 | NSString * WebViewAjax_js(); 16 | //点击事件、资源时序数据和ajax请求及js错误 17 | NSString * WKWebViewJavaScript_js(); -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/WebViewMonitor.framework/Headers/WebViewMonitor.h: -------------------------------------------------------------------------------- 1 | // 2 | // WebViewMonitor.h 3 | // WebViewMonitor 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for WebViewMonitor. 12 | FOUNDATION_EXPORT double WebViewMonitorVersionNumber; 13 | 14 | //! Project version string for WebViewMonitor. 15 | FOUNDATION_EXPORT const unsigned char WebViewMonitorVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | #import 20 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/WebViewMonitor.framework/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LonylyMark/WebViewMonitor/946cb1e349e75fe771c9c725a690e9e2c157f149/WebViewShare/WebViewShare/WebViewMonitor.framework/Info.plist -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/WebViewMonitor.framework/Modules/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module WebViewMonitor { 2 | umbrella header "WebViewMonitor.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/WebViewMonitor.framework/WebViewMonitor: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LonylyMark/WebViewMonitor/946cb1e349e75fe771c9c725a690e9e2c157f149/WebViewShare/WebViewShare/WebViewMonitor.framework/WebViewMonitor -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/WebViewMonitor.framework/_CodeSignature/CodeDirectory: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LonylyMark/WebViewMonitor/946cb1e349e75fe771c9c725a690e9e2c157f149/WebViewShare/WebViewShare/WebViewMonitor.framework/_CodeSignature/CodeDirectory -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/WebViewMonitor.framework/_CodeSignature/CodeRequirements: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LonylyMark/WebViewMonitor/946cb1e349e75fe771c9c725a690e9e2c157f149/WebViewShare/WebViewShare/WebViewMonitor.framework/_CodeSignature/CodeRequirements -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/WebViewMonitor.framework/_CodeSignature/CodeRequirements-1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LonylyMark/WebViewMonitor/946cb1e349e75fe771c9c725a690e9e2c157f149/WebViewShare/WebViewShare/WebViewMonitor.framework/_CodeSignature/CodeRequirements-1 -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/WebViewMonitor.framework/_CodeSignature/CodeResources: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | files 6 | 7 | Headers/WebViewJavaScript_js.h 8 | 9 | w9wUfY/AySxnhkwKv7rZsXCFJhY= 10 | 11 | Headers/WebViewMonitor.h 12 | 13 | 05/xob5w92pbt8cZniYPXUB8S+s= 14 | 15 | Info.plist 16 | 17 | 4A/Sufl71KdMzPtzztfelL/vE7A= 18 | 19 | Modules/module.modulemap 20 | 21 | uD/cLMwL29+x0wMLSrCgyB6rSoI= 22 | 23 | 24 | files2 25 | 26 | Headers/WebViewJavaScript_js.h 27 | 28 | hash 29 | 30 | w9wUfY/AySxnhkwKv7rZsXCFJhY= 31 | 32 | hash2 33 | 34 | yYn0jlGVrMtdWmUuEm90k9Z53b9MRLk4AOGFAoP12Gw= 35 | 36 | 37 | Headers/WebViewMonitor.h 38 | 39 | hash 40 | 41 | 05/xob5w92pbt8cZniYPXUB8S+s= 42 | 43 | hash2 44 | 45 | 406QzKGES9oZbKM3/pa7Hww5KNwBUHRRTArkKz10UuA= 46 | 47 | 48 | Modules/module.modulemap 49 | 50 | hash 51 | 52 | uD/cLMwL29+x0wMLSrCgyB6rSoI= 53 | 54 | hash2 55 | 56 | NcF9pH9tteQDxORxhtIWEnHmOwvdDMY5vqAwrArezaM= 57 | 58 | 59 | 60 | rules 61 | 62 | ^ 63 | 64 | ^.*\.lproj/ 65 | 66 | optional 67 | 68 | weight 69 | 1000 70 | 71 | ^.*\.lproj/locversion.plist$ 72 | 73 | omit 74 | 75 | weight 76 | 1100 77 | 78 | ^version.plist$ 79 | 80 | 81 | rules2 82 | 83 | .*\.dSYM($|/) 84 | 85 | weight 86 | 11 87 | 88 | ^ 89 | 90 | weight 91 | 20 92 | 93 | ^(.*/)?\.DS_Store$ 94 | 95 | omit 96 | 97 | weight 98 | 2000 99 | 100 | ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ 101 | 102 | nested 103 | 104 | weight 105 | 10 106 | 107 | ^.* 108 | 109 | ^.*\.lproj/ 110 | 111 | optional 112 | 113 | weight 114 | 1000 115 | 116 | ^.*\.lproj/locversion.plist$ 117 | 118 | omit 119 | 120 | weight 121 | 1100 122 | 123 | ^Info\.plist$ 124 | 125 | omit 126 | 127 | weight 128 | 20 129 | 130 | ^PkgInfo$ 131 | 132 | omit 133 | 134 | weight 135 | 20 136 | 137 | ^[^/]+$ 138 | 139 | nested 140 | 141 | weight 142 | 10 143 | 144 | ^embedded\.provisionprofile$ 145 | 146 | weight 147 | 20 148 | 149 | ^version\.plist$ 150 | 151 | weight 152 | 20 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/WebViewMonitor.framework/_CodeSignature/CodeSignature: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LonylyMark/WebViewMonitor/946cb1e349e75fe771c9c725a690e9e2c157f149/WebViewShare/WebViewShare/WebViewMonitor.framework/_CodeSignature/CodeSignature -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/WebViewMonitor.framework/_CodeSignature/CodeTopDirectory: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/WebViewTracker.h: -------------------------------------------------------------------------------- 1 | // 2 | // WebViewTracker.h 3 | // WebViewShare 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | typedef void(^WebViewTrackerMonitor)(NSDictionary *payload); 13 | typedef void (^ WebViewTrackerAsyncMonitor)(UIWebView *webView, NSDictionary *payload); 14 | 15 | @interface WebViewTracker : NSObject 16 | + (id)shareInstance; 17 | + (BOOL)webView:(UIWebView*)webView withUrl:(NSURL*)url; 18 | @end 19 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/WebViewTracker.m: -------------------------------------------------------------------------------- 1 | // 2 | // WebViewTracker.m 3 | // WebViewShare 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import "WebViewTracker.h" 10 | #import 11 | @interface WebViewTracker() 12 | @property (strong, nonatomic) NSMutableDictionary *listeners; 13 | @end 14 | @implementation WebViewTracker 15 | + (id)shareInstance; 16 | { 17 | static dispatch_once_t once; 18 | static WebViewTracker *instance; 19 | dispatch_once(&once, ^{ 20 | instance = [[self alloc] init]; 21 | instance.listeners = [[NSMutableDictionary alloc] init]; 22 | }); 23 | return instance; 24 | } 25 | void WebViewSwizzle(Class c, SEL orig, SEL newS) { 26 | 27 | Method origMethod = class_getInstanceMethod(c, orig); 28 | Method newMethod = class_getInstanceMethod(c, newS); 29 | if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) { 30 | class_replaceMethod(c, newS, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); 31 | } else { 32 | method_exchangeImplementations(origMethod, newMethod); 33 | } 34 | } 35 | + (void)sendType:(NSString *)type perform:(WebViewTrackerMonitor)monitor 36 | { 37 | void (^ extend)(UIWebView *webView,NSDictionary *payload) = ^(UIWebView *webView,NSDictionary *payload){ 38 | monitor(payload); 39 | 40 | }; 41 | [self sendType:type addType:extend]; 42 | } 43 | + (void)sendType:(NSString *)type addType:(WebViewTrackerAsyncMonitor)monitor 44 | { 45 | WebViewTracker *instance = [WebViewTracker shareInstance]; 46 | 47 | NSDictionary *listeners = [instance listeners]; 48 | 49 | NSMutableArray *listenerList = [listeners objectForKey:type]; 50 | 51 | if (listenerList == nil) { 52 | listenerList = [[NSMutableArray alloc] init]; 53 | 54 | [instance.listeners setValue:listenerList forKey:type]; 55 | [listenerList addObject:monitor]; 56 | } 57 | } 58 | 59 | + (BOOL)webView:(UIWebView*)webView withUrl:(NSURL*)url 60 | { 61 | if ([[url scheme] isEqualToString:@"cloudwise-agent"]) { 62 | 63 | NSString *eventType = [url host]; 64 | NSString *query = [url query]; 65 | NSString *jsonString = [query stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 66 | 67 | NSError *error; 68 | NSDictionary *JSON = [NSJSONSerialization 69 | JSONObjectWithData: [jsonString dataUsingEncoding:NSUTF8StringEncoding] 70 | options: NSJSONReadingAllowFragments 71 | error: &error]; 72 | //时间响应数据 73 | if ([eventType isEqualToString:@"timing"]) 74 | { 75 | [[self shareInstance] triggerEventFromWebView:webView withData:JSON]; 76 | 77 | }else if ([eventType isEqualToString:@"ajax"])//ajax请求数据 78 | { 79 | [[self shareInstance] triggerEventFromWebView:webView withData:JSON]; 80 | } 81 | 82 | return NO; 83 | } 84 | 85 | 86 | if ([[url scheme] isEqualToString:@"cloudwise"] ) 87 | { 88 | NSString *eventType = [url host]; 89 | // NSString *messageId = [[url path] substringFromIndex:1]; 90 | NSString *query = [url query]; 91 | NSString *jsonString = [query stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 92 | 93 | NSError *error; 94 | NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData: 95 | [jsonString dataUsingEncoding:NSUTF8StringEncoding] 96 | options: NSJSONReadingMutableContainers 97 | error: &error]; 98 | 99 | if ([eventType isEqualToString:@"event"]) { 100 | [[self shareInstance] triggerEventFromWebView:webView withData:JSON]; 101 | } 102 | 103 | return NO; 104 | } 105 | 106 | return YES; 107 | } 108 | 109 | - (void)triggerEventFromWebView:(UIWebView*)webView withData:(NSDictionary*)envelope 110 | { 111 | 112 | NSDictionary *listeners = [[WebViewTracker shareInstance] listeners]; 113 | 114 | NSString *type = [envelope objectForKey:@"type"]; 115 | 116 | NSDictionary *payload = [envelope objectForKey:@"payload"]; 117 | NSArray *listenerList = (NSArray*)[listeners objectForKey:type]; 118 | 119 | for (WebViewTrackerAsyncMonitor handler in listenerList) 120 | { 121 | handler(webView, payload); 122 | } 123 | 124 | } 125 | 126 | 127 | @end 128 | 129 | @interface UIWebView (Monitor) 130 | 131 | @end 132 | @implementation UIWebView (Monitor) 133 | 134 | +(void)load 135 | { 136 | static dispatch_once_t onceToken; 137 | dispatch_once(&onceToken, ^{ 138 | Class webViewCls = [UIWebView class]; 139 | WebViewSwizzle(webViewCls, @selector(loadRequest:), sel_registerName("webViewMonitor_loadRequest:")); 140 | 141 | WebViewSwizzle(webViewCls, @selector(loadHTMLString:baseURL:), sel_registerName("webViewMonitor_loadHTMLString:baseURL:")); 142 | 143 | WebViewSwizzle(webViewCls, @selector(loadData:MIMEType:textEncodingName:baseURL:), sel_registerName("webViewMonitor_loadData:MIMEType:textEncodingName:baseURL:")); 144 | }); 145 | } 146 | - (void)webViewMonitor_loadRequest:(NSURLRequest *)request 147 | { 148 | [self webViewMonitor_loadRequest:request]; 149 | webViewMonitor(self); 150 | } 151 | - (void)webViewMonitor_loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL 152 | { 153 | [self webViewMonitor_loadHTMLString:string baseURL:baseURL]; 154 | webViewMonitor(self); 155 | } 156 | - (void)webViewMonitor_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)textEncodingName baseURL:(NSURL *)baseURL 157 | { 158 | [self webViewMonitor_loadData:data MIMEType:MIMEType textEncodingName:textEncodingName baseURL:baseURL]; 159 | webViewMonitor(self); 160 | 161 | } 162 | 163 | static void webViewMonitor(UIWebView *ui_self) 164 | { 165 | //行为事件数据 166 | [WebViewTracker sendType:@"onclick" perform:^(NSDictionary *payload) { 167 | NSLog(@"payload=%@",payload); 168 | }]; 169 | //响应事件数据和js错误 170 | [WebViewTracker sendType:@"cloudwise_monitor" perform:^(NSDictionary *payload) { 171 | NSLog(@"timing=%@",payload); 172 | }]; 173 | //ajax数据 174 | [WebViewTracker sendType:@"cloudwise_monitor_ajax" perform:^(NSDictionary *payload) { 175 | NSLog(@"ajax=%@",payload); 176 | }]; 177 | } 178 | @end 179 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShare/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // WebViewShare 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShareTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShareTests/WebViewShareTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // WebViewShareTests.m 3 | // WebViewShareTests 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface WebViewShareTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation WebViewShareTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShareUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /WebViewShare/WebViewShareUITests/WebViewShareUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // WebViewShareUITests.m 3 | // WebViewShareUITests 4 | // 5 | // Created by cyan color on 16/4/25. 6 | // Copyright © 2016年 com.mobile. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface WebViewShareUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation WebViewShareUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // 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. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | --------------------------------------------------------------------------------