├── .gitignore ├── LICENSE ├── QiWKWebView.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── QiWKWebView ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Basic │ ├── QiLink.html │ ├── QiWKDetailViewController.h │ ├── QiWKDetailViewController.m │ ├── QiWKWebViewController.h │ └── QiWKWebViewController.m ├── Custom │ ├── QiContentRule.html │ ├── QiCustomResource.html │ ├── QiCustomSchemeHandler.h │ ├── QiCustomSchemeHandler.m │ ├── QiCustomWKWebViewController.h │ ├── QiCustomWKWebViewController.m │ ├── QiWKScriptViewController.h │ └── QiWKScriptViewController.m ├── Info.plist ├── SceneDelegate.h ├── SceneDelegate.m ├── ViewController.h ├── ViewController.m └── main.m └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots/**/*.png 56 | fastlane/test_output 57 | 58 | # Code Injection 59 | # 60 | # After new code Injection tools there's a generated folder /iOSInjectionProject 61 | # https://github.com/johnno1962/injectionforxcode 62 | 63 | iOSInjectionProject/ 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 iOS及周边技术文章分享平台。 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /QiWKWebView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | EE5C8224236FCB4000ABA8BF /* QiCustomWKWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EE5C8223236FCB4000ABA8BF /* QiCustomWKWebViewController.m */; }; 11 | EE5C8227236FCB7D00ABA8BF /* QiCustomSchemeHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = EE5C8226236FCB7D00ABA8BF /* QiCustomSchemeHandler.m */; }; 12 | EE5C822C236FCBD000ABA8BF /* QiCustomResource.html in Resources */ = {isa = PBXBuildFile; fileRef = EE5C822B236FCBD000ABA8BF /* QiCustomResource.html */; }; 13 | EE5C8232237030A200ABA8BF /* QiWKScriptViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EE5C8231237030A200ABA8BF /* QiWKScriptViewController.m */; }; 14 | EE5D5BFF237132AE00B8E95D /* QiContentRule.html in Resources */ = {isa = PBXBuildFile; fileRef = EE5D5BFE237132AE00B8E95D /* QiContentRule.html */; }; 15 | EEB8BBC7234C455000C9DF71 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = EEB8BBC6234C455000C9DF71 /* AppDelegate.m */; }; 16 | EEB8BBCA234C455000C9DF71 /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = EEB8BBC9234C455000C9DF71 /* SceneDelegate.m */; }; 17 | EEB8BBCD234C455000C9DF71 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EEB8BBCC234C455000C9DF71 /* ViewController.m */; }; 18 | EEB8BBD0234C455000C9DF71 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EEB8BBCE234C455000C9DF71 /* Main.storyboard */; }; 19 | EEB8BBD2234C455400C9DF71 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EEB8BBD1234C455400C9DF71 /* Assets.xcassets */; }; 20 | EEB8BBD5234C455400C9DF71 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EEB8BBD3234C455400C9DF71 /* LaunchScreen.storyboard */; }; 21 | EEB8BBD8234C455400C9DF71 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = EEB8BBD7234C455400C9DF71 /* main.m */; }; 22 | EEB8BBE0234C45A800C9DF71 /* QiWKWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EEB8BBDF234C45A800C9DF71 /* QiWKWebViewController.m */; }; 23 | EEB8BBE3234C930900C9DF71 /* QiWKDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EEB8BBE2234C930900C9DF71 /* QiWKDetailViewController.m */; }; 24 | EEB8BBE5234DBEAE00C9DF71 /* QiLink.html in Resources */ = {isa = PBXBuildFile; fileRef = EEB8BBE4234DBEAD00C9DF71 /* QiLink.html */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | EE5C8222236FCB4000ABA8BF /* QiCustomWKWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QiCustomWKWebViewController.h; sourceTree = ""; }; 29 | EE5C8223236FCB4000ABA8BF /* QiCustomWKWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QiCustomWKWebViewController.m; sourceTree = ""; }; 30 | EE5C8225236FCB7D00ABA8BF /* QiCustomSchemeHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QiCustomSchemeHandler.h; sourceTree = ""; }; 31 | EE5C8226236FCB7D00ABA8BF /* QiCustomSchemeHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QiCustomSchemeHandler.m; sourceTree = ""; }; 32 | EE5C822B236FCBD000ABA8BF /* QiCustomResource.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = QiCustomResource.html; sourceTree = ""; }; 33 | EE5C8230237030A200ABA8BF /* QiWKScriptViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QiWKScriptViewController.h; sourceTree = ""; }; 34 | EE5C8231237030A200ABA8BF /* QiWKScriptViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QiWKScriptViewController.m; sourceTree = ""; }; 35 | EE5D5BFE237132AE00B8E95D /* QiContentRule.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = QiContentRule.html; sourceTree = ""; }; 36 | EEB8BBC2234C455000C9DF71 /* QiWKWebView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = QiWKWebView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | EEB8BBC5234C455000C9DF71 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 38 | EEB8BBC6234C455000C9DF71 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 39 | EEB8BBC8234C455000C9DF71 /* SceneDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = ""; }; 40 | EEB8BBC9234C455000C9DF71 /* SceneDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = ""; }; 41 | EEB8BBCB234C455000C9DF71 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 42 | EEB8BBCC234C455000C9DF71 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 43 | EEB8BBCF234C455000C9DF71 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 44 | EEB8BBD1234C455400C9DF71 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 45 | EEB8BBD4234C455400C9DF71 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 46 | EEB8BBD6234C455400C9DF71 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 47 | EEB8BBD7234C455400C9DF71 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 48 | EEB8BBDE234C45A800C9DF71 /* QiWKWebViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QiWKWebViewController.h; sourceTree = ""; }; 49 | EEB8BBDF234C45A800C9DF71 /* QiWKWebViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QiWKWebViewController.m; sourceTree = ""; }; 50 | EEB8BBE1234C930900C9DF71 /* QiWKDetailViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QiWKDetailViewController.h; sourceTree = ""; }; 51 | EEB8BBE2234C930900C9DF71 /* QiWKDetailViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QiWKDetailViewController.m; sourceTree = ""; }; 52 | EEB8BBE4234DBEAD00C9DF71 /* QiLink.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = QiLink.html; sourceTree = ""; }; 53 | /* End PBXFileReference section */ 54 | 55 | /* Begin PBXFrameworksBuildPhase section */ 56 | EEB8BBBF234C455000C9DF71 /* Frameworks */ = { 57 | isa = PBXFrameworksBuildPhase; 58 | buildActionMask = 2147483647; 59 | files = ( 60 | ); 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | /* End PBXFrameworksBuildPhase section */ 64 | 65 | /* Begin PBXGroup section */ 66 | EE5C8221236FCB3200ABA8BF /* Custom */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | EE5D5BFE237132AE00B8E95D /* QiContentRule.html */, 70 | EE5C822B236FCBD000ABA8BF /* QiCustomResource.html */, 71 | EE5C8222236FCB4000ABA8BF /* QiCustomWKWebViewController.h */, 72 | EE5C8223236FCB4000ABA8BF /* QiCustomWKWebViewController.m */, 73 | EE5C8225236FCB7D00ABA8BF /* QiCustomSchemeHandler.h */, 74 | EE5C8226236FCB7D00ABA8BF /* QiCustomSchemeHandler.m */, 75 | EE5C8230237030A200ABA8BF /* QiWKScriptViewController.h */, 76 | EE5C8231237030A200ABA8BF /* QiWKScriptViewController.m */, 77 | ); 78 | path = Custom; 79 | sourceTree = ""; 80 | }; 81 | EE5C822D236FCBE000ABA8BF /* Basic */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | EEB8BBE4234DBEAD00C9DF71 /* QiLink.html */, 85 | EEB8BBDE234C45A800C9DF71 /* QiWKWebViewController.h */, 86 | EEB8BBDF234C45A800C9DF71 /* QiWKWebViewController.m */, 87 | EEB8BBE1234C930900C9DF71 /* QiWKDetailViewController.h */, 88 | EEB8BBE2234C930900C9DF71 /* QiWKDetailViewController.m */, 89 | ); 90 | path = Basic; 91 | sourceTree = ""; 92 | }; 93 | EEB8BBB9234C455000C9DF71 = { 94 | isa = PBXGroup; 95 | children = ( 96 | EEB8BBC4234C455000C9DF71 /* QiWKWebView */, 97 | EEB8BBC3234C455000C9DF71 /* Products */, 98 | ); 99 | sourceTree = ""; 100 | }; 101 | EEB8BBC3234C455000C9DF71 /* Products */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | EEB8BBC2234C455000C9DF71 /* QiWKWebView.app */, 105 | ); 106 | name = Products; 107 | sourceTree = ""; 108 | }; 109 | EEB8BBC4234C455000C9DF71 /* QiWKWebView */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | EE5C8221236FCB3200ABA8BF /* Custom */, 113 | EE5C822D236FCBE000ABA8BF /* Basic */, 114 | EEB8BBC5234C455000C9DF71 /* AppDelegate.h */, 115 | EEB8BBC6234C455000C9DF71 /* AppDelegate.m */, 116 | EEB8BBC8234C455000C9DF71 /* SceneDelegate.h */, 117 | EEB8BBC9234C455000C9DF71 /* SceneDelegate.m */, 118 | EEB8BBCB234C455000C9DF71 /* ViewController.h */, 119 | EEB8BBCC234C455000C9DF71 /* ViewController.m */, 120 | EEB8BBCE234C455000C9DF71 /* Main.storyboard */, 121 | EEB8BBD1234C455400C9DF71 /* Assets.xcassets */, 122 | EEB8BBD3234C455400C9DF71 /* LaunchScreen.storyboard */, 123 | EEB8BBD6234C455400C9DF71 /* Info.plist */, 124 | EEB8BBD7234C455400C9DF71 /* main.m */, 125 | ); 126 | path = QiWKWebView; 127 | sourceTree = ""; 128 | }; 129 | /* End PBXGroup section */ 130 | 131 | /* Begin PBXNativeTarget section */ 132 | EEB8BBC1234C455000C9DF71 /* QiWKWebView */ = { 133 | isa = PBXNativeTarget; 134 | buildConfigurationList = EEB8BBDB234C455400C9DF71 /* Build configuration list for PBXNativeTarget "QiWKWebView" */; 135 | buildPhases = ( 136 | EEB8BBBE234C455000C9DF71 /* Sources */, 137 | EEB8BBBF234C455000C9DF71 /* Frameworks */, 138 | EEB8BBC0234C455000C9DF71 /* Resources */, 139 | ); 140 | buildRules = ( 141 | ); 142 | dependencies = ( 143 | ); 144 | name = QiWKWebView; 145 | productName = QiWKWebView; 146 | productReference = EEB8BBC2234C455000C9DF71 /* QiWKWebView.app */; 147 | productType = "com.apple.product-type.application"; 148 | }; 149 | /* End PBXNativeTarget section */ 150 | 151 | /* Begin PBXProject section */ 152 | EEB8BBBA234C455000C9DF71 /* Project object */ = { 153 | isa = PBXProject; 154 | attributes = { 155 | LastUpgradeCheck = 1100; 156 | ORGANIZATIONNAME = WYW; 157 | TargetAttributes = { 158 | EEB8BBC1234C455000C9DF71 = { 159 | CreatedOnToolsVersion = 11.0; 160 | }; 161 | }; 162 | }; 163 | buildConfigurationList = EEB8BBBD234C455000C9DF71 /* Build configuration list for PBXProject "QiWKWebView" */; 164 | compatibilityVersion = "Xcode 9.3"; 165 | developmentRegion = en; 166 | hasScannedForEncodings = 0; 167 | knownRegions = ( 168 | en, 169 | Base, 170 | ); 171 | mainGroup = EEB8BBB9234C455000C9DF71; 172 | productRefGroup = EEB8BBC3234C455000C9DF71 /* Products */; 173 | projectDirPath = ""; 174 | projectRoot = ""; 175 | targets = ( 176 | EEB8BBC1234C455000C9DF71 /* QiWKWebView */, 177 | ); 178 | }; 179 | /* End PBXProject section */ 180 | 181 | /* Begin PBXResourcesBuildPhase section */ 182 | EEB8BBC0234C455000C9DF71 /* Resources */ = { 183 | isa = PBXResourcesBuildPhase; 184 | buildActionMask = 2147483647; 185 | files = ( 186 | EEB8BBD5234C455400C9DF71 /* LaunchScreen.storyboard in Resources */, 187 | EE5C822C236FCBD000ABA8BF /* QiCustomResource.html in Resources */, 188 | EEB8BBD2234C455400C9DF71 /* Assets.xcassets in Resources */, 189 | EEB8BBE5234DBEAE00C9DF71 /* QiLink.html in Resources */, 190 | EE5D5BFF237132AE00B8E95D /* QiContentRule.html in Resources */, 191 | EEB8BBD0234C455000C9DF71 /* Main.storyboard in Resources */, 192 | ); 193 | runOnlyForDeploymentPostprocessing = 0; 194 | }; 195 | /* End PBXResourcesBuildPhase section */ 196 | 197 | /* Begin PBXSourcesBuildPhase section */ 198 | EEB8BBBE234C455000C9DF71 /* Sources */ = { 199 | isa = PBXSourcesBuildPhase; 200 | buildActionMask = 2147483647; 201 | files = ( 202 | EEB8BBE0234C45A800C9DF71 /* QiWKWebViewController.m in Sources */, 203 | EEB8BBE3234C930900C9DF71 /* QiWKDetailViewController.m in Sources */, 204 | EE5C8227236FCB7D00ABA8BF /* QiCustomSchemeHandler.m in Sources */, 205 | EE5C8232237030A200ABA8BF /* QiWKScriptViewController.m in Sources */, 206 | EEB8BBCD234C455000C9DF71 /* ViewController.m in Sources */, 207 | EEB8BBC7234C455000C9DF71 /* AppDelegate.m in Sources */, 208 | EE5C8224236FCB4000ABA8BF /* QiCustomWKWebViewController.m in Sources */, 209 | EEB8BBD8234C455400C9DF71 /* main.m in Sources */, 210 | EEB8BBCA234C455000C9DF71 /* SceneDelegate.m in Sources */, 211 | ); 212 | runOnlyForDeploymentPostprocessing = 0; 213 | }; 214 | /* End PBXSourcesBuildPhase section */ 215 | 216 | /* Begin PBXVariantGroup section */ 217 | EEB8BBCE234C455000C9DF71 /* Main.storyboard */ = { 218 | isa = PBXVariantGroup; 219 | children = ( 220 | EEB8BBCF234C455000C9DF71 /* Base */, 221 | ); 222 | name = Main.storyboard; 223 | sourceTree = ""; 224 | }; 225 | EEB8BBD3234C455400C9DF71 /* LaunchScreen.storyboard */ = { 226 | isa = PBXVariantGroup; 227 | children = ( 228 | EEB8BBD4234C455400C9DF71 /* Base */, 229 | ); 230 | name = LaunchScreen.storyboard; 231 | sourceTree = ""; 232 | }; 233 | /* End PBXVariantGroup section */ 234 | 235 | /* Begin XCBuildConfiguration section */ 236 | EEB8BBD9234C455400C9DF71 /* Debug */ = { 237 | isa = XCBuildConfiguration; 238 | buildSettings = { 239 | ALWAYS_SEARCH_USER_PATHS = NO; 240 | CLANG_ANALYZER_NONNULL = YES; 241 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 242 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 243 | CLANG_CXX_LIBRARY = "libc++"; 244 | CLANG_ENABLE_MODULES = YES; 245 | CLANG_ENABLE_OBJC_ARC = YES; 246 | CLANG_ENABLE_OBJC_WEAK = YES; 247 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 248 | CLANG_WARN_BOOL_CONVERSION = YES; 249 | CLANG_WARN_COMMA = YES; 250 | CLANG_WARN_CONSTANT_CONVERSION = YES; 251 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 252 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 253 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 254 | CLANG_WARN_EMPTY_BODY = YES; 255 | CLANG_WARN_ENUM_CONVERSION = YES; 256 | CLANG_WARN_INFINITE_RECURSION = YES; 257 | CLANG_WARN_INT_CONVERSION = YES; 258 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 259 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 260 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 261 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 262 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 263 | CLANG_WARN_STRICT_PROTOTYPES = YES; 264 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 265 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 266 | CLANG_WARN_UNREACHABLE_CODE = YES; 267 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 268 | COPY_PHASE_STRIP = NO; 269 | DEBUG_INFORMATION_FORMAT = dwarf; 270 | ENABLE_STRICT_OBJC_MSGSEND = YES; 271 | ENABLE_TESTABILITY = YES; 272 | GCC_C_LANGUAGE_STANDARD = gnu11; 273 | GCC_DYNAMIC_NO_PIC = NO; 274 | GCC_NO_COMMON_BLOCKS = YES; 275 | GCC_OPTIMIZATION_LEVEL = 0; 276 | GCC_PREPROCESSOR_DEFINITIONS = ( 277 | "DEBUG=1", 278 | "$(inherited)", 279 | ); 280 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 281 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 282 | GCC_WARN_UNDECLARED_SELECTOR = YES; 283 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 284 | GCC_WARN_UNUSED_FUNCTION = YES; 285 | GCC_WARN_UNUSED_VARIABLE = YES; 286 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 287 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 288 | MTL_FAST_MATH = YES; 289 | ONLY_ACTIVE_ARCH = YES; 290 | SDKROOT = iphoneos; 291 | }; 292 | name = Debug; 293 | }; 294 | EEB8BBDA234C455400C9DF71 /* Release */ = { 295 | isa = XCBuildConfiguration; 296 | buildSettings = { 297 | ALWAYS_SEARCH_USER_PATHS = NO; 298 | CLANG_ANALYZER_NONNULL = YES; 299 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 300 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 301 | CLANG_CXX_LIBRARY = "libc++"; 302 | CLANG_ENABLE_MODULES = YES; 303 | CLANG_ENABLE_OBJC_ARC = YES; 304 | CLANG_ENABLE_OBJC_WEAK = YES; 305 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 306 | CLANG_WARN_BOOL_CONVERSION = YES; 307 | CLANG_WARN_COMMA = YES; 308 | CLANG_WARN_CONSTANT_CONVERSION = YES; 309 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 310 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 311 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 312 | CLANG_WARN_EMPTY_BODY = YES; 313 | CLANG_WARN_ENUM_CONVERSION = YES; 314 | CLANG_WARN_INFINITE_RECURSION = YES; 315 | CLANG_WARN_INT_CONVERSION = YES; 316 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 317 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 318 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 319 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 320 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 321 | CLANG_WARN_STRICT_PROTOTYPES = YES; 322 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 323 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 324 | CLANG_WARN_UNREACHABLE_CODE = YES; 325 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 326 | COPY_PHASE_STRIP = NO; 327 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 328 | ENABLE_NS_ASSERTIONS = NO; 329 | ENABLE_STRICT_OBJC_MSGSEND = YES; 330 | GCC_C_LANGUAGE_STANDARD = gnu11; 331 | GCC_NO_COMMON_BLOCKS = YES; 332 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 333 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 334 | GCC_WARN_UNDECLARED_SELECTOR = YES; 335 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 336 | GCC_WARN_UNUSED_FUNCTION = YES; 337 | GCC_WARN_UNUSED_VARIABLE = YES; 338 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 339 | MTL_ENABLE_DEBUG_INFO = NO; 340 | MTL_FAST_MATH = YES; 341 | SDKROOT = iphoneos; 342 | VALIDATE_PRODUCT = YES; 343 | }; 344 | name = Release; 345 | }; 346 | EEB8BBDC234C455400C9DF71 /* Debug */ = { 347 | isa = XCBuildConfiguration; 348 | buildSettings = { 349 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 350 | CODE_SIGN_STYLE = Automatic; 351 | DEVELOPMENT_TEAM = 8ZX24TX624; 352 | INFOPLIST_FILE = QiWKWebView/Info.plist; 353 | LD_RUNPATH_SEARCH_PATHS = ( 354 | "$(inherited)", 355 | "@executable_path/Frameworks", 356 | ); 357 | PRODUCT_BUNDLE_IDENTIFIER = com.qishare.ios.wyw; 358 | PRODUCT_NAME = "$(TARGET_NAME)"; 359 | TARGETED_DEVICE_FAMILY = "1,2"; 360 | }; 361 | name = Debug; 362 | }; 363 | EEB8BBDD234C455400C9DF71 /* Release */ = { 364 | isa = XCBuildConfiguration; 365 | buildSettings = { 366 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 367 | CODE_SIGN_STYLE = Automatic; 368 | DEVELOPMENT_TEAM = 8ZX24TX624; 369 | INFOPLIST_FILE = QiWKWebView/Info.plist; 370 | LD_RUNPATH_SEARCH_PATHS = ( 371 | "$(inherited)", 372 | "@executable_path/Frameworks", 373 | ); 374 | PRODUCT_BUNDLE_IDENTIFIER = com.qishare.ios.wyw; 375 | PRODUCT_NAME = "$(TARGET_NAME)"; 376 | TARGETED_DEVICE_FAMILY = "1,2"; 377 | }; 378 | name = Release; 379 | }; 380 | /* End XCBuildConfiguration section */ 381 | 382 | /* Begin XCConfigurationList section */ 383 | EEB8BBBD234C455000C9DF71 /* Build configuration list for PBXProject "QiWKWebView" */ = { 384 | isa = XCConfigurationList; 385 | buildConfigurations = ( 386 | EEB8BBD9234C455400C9DF71 /* Debug */, 387 | EEB8BBDA234C455400C9DF71 /* Release */, 388 | ); 389 | defaultConfigurationIsVisible = 0; 390 | defaultConfigurationName = Release; 391 | }; 392 | EEB8BBDB234C455400C9DF71 /* Build configuration list for PBXNativeTarget "QiWKWebView" */ = { 393 | isa = XCConfigurationList; 394 | buildConfigurations = ( 395 | EEB8BBDC234C455400C9DF71 /* Debug */, 396 | EEB8BBDD234C455400C9DF71 /* Release */, 397 | ); 398 | defaultConfigurationIsVisible = 0; 399 | defaultConfigurationName = Release; 400 | }; 401 | /* End XCConfigurationList section */ 402 | }; 403 | rootObject = EEB8BBBA234C455000C9DF71 /* Project object */; 404 | } 405 | -------------------------------------------------------------------------------- /QiWKWebView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /QiWKWebView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /QiWKWebView/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // QiWKWebView 4 | // 5 | // Created by wangyongwang on 2019/10/8. 6 | // Copyright © 2019 QiShare. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (nonatomic, strong) UIWindow *window; 14 | 15 | @end 16 | 17 | -------------------------------------------------------------------------------- /QiWKWebView/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // QiWKWebView 4 | // 5 | // Created by wangyongwang on 2019/10/8. 6 | // Copyright © 2019 QiShare. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "QiWKWebViewController.h" 11 | #import "ViewController.h" 12 | 13 | @implementation AppDelegate 14 | 15 | 16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 17 | 18 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 19 | ViewController *vc = [ViewController new]; 20 | UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc]; 21 | self.window.rootViewController = nav; 22 | [self.window makeKeyAndVisible]; 23 | return YES; 24 | } 25 | 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /QiWKWebView/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /QiWKWebView/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /QiWKWebView/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 | -------------------------------------------------------------------------------- /QiWKWebView/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /QiWKWebView/Basic/QiLink.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QiWKWebView 6 | 13 | 14 | 15 | 16 | window 打开so.com 17 |
18 | blank 打开so.com 19 |
20 | self so.com 21 |
22 | parent so.com 23 |
24 | top so.com 25 | 26 |
27 | 发送邮件 28 |
29 | 给10086,10010发信息 30 |
31 | 给10086打电话 32 | 33 |

未添加链接的虚拟号码 12345678910

34 | 35 |

36 | 37 | 38 | 39 | 68 | 69 | 70 | 71 | 72 |
73 | 74 |
75 | 76 |
77 | 78 | 79 | 80 |

81 | 注意: 单词之间的空格使用 %20 代替,以确保浏览器可以正常显示文本。 82 |

83 | 84 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /QiWKWebView/Basic/QiWKDetailViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // QiWKDetailViewController.h 3 | // QiWKWebView 4 | // 5 | // Created by wangyongwang on 2019/10/8. 6 | // Copyright © 2019 QiShare. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface QiWKDetailViewController : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /QiWKWebView/Basic/QiWKDetailViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // QiWKDetailViewController.m 3 | // QiWKWebView 4 | // 5 | // Created by wangyongwang on 2019/10/8. 6 | // Copyright © 2019 QiShare. All rights reserved. 7 | // 8 | 9 | #import "QiWKDetailViewController.h" 10 | #import 11 | 12 | @interface QiWKDetailViewController () 13 | 14 | @property (nonatomic, strong) WKWebView *webView; 15 | 16 | @end 17 | 18 | @implementation QiWKDetailViewController 19 | 20 | - (void)loadView { 21 | 22 | WKWebViewConfiguration *webConfig = [WKWebViewConfiguration new]; 23 | webConfig.dataDetectorTypes = WKDataDetectorTypePhoneNumber; 24 | _webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:webConfig]; 25 | _webView.allowsBackForwardNavigationGestures = YES; 26 | _webView.backgroundColor = [UIColor whiteColor]; 27 | self.view = _webView; 28 | } 29 | 30 | - (void)viewDidLoad { 31 | [super viewDidLoad]; 32 | 33 | self.title = @"WKWebView常见问题"; 34 | UIBarButtonItem *leftItem = [[UIBarButtonItem alloc] initWithTitle:@"WKBack" style:UIBarButtonItemStylePlain target:self action:@selector(leftItemClicked:)]; 35 | self.navigationItem.leftBarButtonItem = leftItem; 36 | 37 | _webView.UIDelegate = self; 38 | _webView.navigationDelegate = self; 39 | [_webView loadFileURL:[[NSBundle mainBundle] URLForResource:@"QiLink" withExtension:@"html"] allowingReadAccessToURL:[[NSBundle mainBundle] bundleURL]]; 40 | /* 41 | NSString *localHtmlStr = [[NSString alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"QiLink" ofType:@"html"] encoding:NSUTF8StringEncoding error:nil]; 42 | [_webView loadHTMLString:localHtmlStr baseURL:[[NSBundle mainBundle] bundleURL]]; 43 | */ 44 | } 45 | 46 | - (void)leftItemClicked:(UIBarButtonItem *)sender { 47 | 48 | if ([self.webView canGoBack]) { 49 | [self.webView goBack]; 50 | return; 51 | } 52 | NSArray *viewControllers = self.navigationController.viewControllers; 53 | NSInteger index = viewControllers.count - 2 > 0 ? viewControllers.count - 2 : 0; 54 | [self.navigationController popToViewController:viewControllers[index] animated:YES]; 55 | } 56 | 57 | #pragma mark - Delegates 58 | 59 | #pragma mark - UIDelegate 60 | // creates a new web view. 61 | // The web view returned must be created with the specified configuration. WebKit loads the request in the returned web view. 62 | - (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{ 63 | 64 | if (!navigationAction.targetFrame) { 65 | [webView loadRequest:navigationAction.request]; 66 | } 67 | return nil; 68 | /* // 跳转到Safari打开url 69 | if (navigationAction.request.URL) { 70 | 71 | NSURL *url = navigationAction.request.URL; 72 | if ([navigationAction.request.URL.absoluteString hasPrefix:@"http"]) { 73 | [[UIApplication sharedApplication] openURL:url options:@{UIApplicationOpenURLOptionUniversalLinksOnly: @(NO)} completionHandler:^(BOOL success) { 74 | NSLog(@"success:%@", @(success)); 75 | }]; 76 | } 77 | } 78 | return nil; 79 | */ 80 | } 81 | 82 | //! Alert弹框 83 | - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler { 84 | 85 | UIAlertController * alertController = [UIAlertController alertControllerWithTitle:@"提示" message:message ? : @"" preferredStyle:UIAlertControllerStyleAlert]; 86 | UIAlertAction * action = [UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 87 | completionHandler(); 88 | }]; 89 | [alertController addAction:action]; 90 | [self presentViewController:alertController animated:YES completion:nil]; 91 | } 92 | 93 | //! Confirm弹框 94 | - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler { 95 | 96 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:message ?: @"" preferredStyle:UIAlertControllerStyleAlert]; 97 | UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 98 | completionHandler(YES); 99 | }]; 100 | UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { 101 | completionHandler(NO); 102 | }]; 103 | 104 | [alertController addAction:confirmAction]; 105 | [alertController addAction:cancelAction]; 106 | 107 | [self presentViewController:alertController animated:YES completion:nil]; 108 | } 109 | 110 | //! prompt弹框 111 | - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler { 112 | 113 | UIAlertController * alertController = [UIAlertController alertControllerWithTitle:prompt message:@"" preferredStyle:UIAlertControllerStyleAlert]; 114 | [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { 115 | textField.text = defaultText; 116 | }]; 117 | UIAlertAction * action = [UIAlertAction actionWithTitle:@"完成" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 118 | completionHandler(alertController.textFields[0].text ? : @""); 119 | }]; 120 | [alertController addAction:action]; 121 | 122 | [self presentViewController:alertController animated:YES completion:nil]; 123 | } 124 | 125 | // Decides whether to allow or cancel a navigation. 126 | - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { 127 | 128 | NSURL *url = navigationAction.request.URL; 129 | 130 | if ([url.absoluteString hasPrefix:@"http"]) { 131 | // The target frame, or nil if this is a new window navigation. 132 | if (!navigationAction.targetFrame) { 133 | [webView loadRequest:navigationAction.request]; 134 | } 135 | decisionHandler(WKNavigationActionPolicyAllow); 136 | } else if ([url.absoluteString hasPrefix:@"file://"]) { 137 | // 加载本地文件 138 | if (!navigationAction.targetFrame) { 139 | [webView loadRequest:navigationAction.request]; 140 | } 141 | decisionHandler(WKNavigationActionPolicyAllow); 142 | } else { 143 | if ([[UIApplication sharedApplication] canOpenURL:url]) { 144 | [[UIApplication sharedApplication] openURL:url options:@{UIApplicationOpenURLOptionUniversalLinksOnly: @(NO)} completionHandler:^(BOOL success) { 145 | // 成功调起三方App之后 146 | NSLog(@"success:%@", @(success)); 147 | }]; 148 | decisionHandler(WKNavigationActionPolicyCancel); 149 | } else { 150 | // was called more than once' 151 | decisionHandler(WKNavigationActionPolicyCancel); 152 | } 153 | } 154 | } 155 | 156 | //// Decides whether to allow or cancel a navigation. 157 | //- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { 158 | // 159 | // NSLog(@"%@", webView.URL); 160 | // NSLog(@"%@", navigationAction.request.URL); 161 | // NSURL *url = navigationAction.request.URL; 162 | // 163 | // if ([url.absoluteString hasPrefix:@"http"]) { 164 | // // The target frame, or nil if this is a new window navigation. 165 | //// if (!navigationAction.targetFrame) { 166 | //// [webView loadRequest:navigationAction.request]; 167 | //// } 168 | //// decisionHandler(WKNavigationActionPolicyAllow); 169 | // } 170 | // decisionHandler(WKNavigationActionPolicyAllow); 171 | //} 172 | 173 | /* 174 | - (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error { 175 | 176 | NSLog(@"错误信息:%@", error); 177 | if (error.code == -999) { 178 | return; 179 | } 180 | } 181 | */ 182 | 183 | 184 | @end 185 | -------------------------------------------------------------------------------- /QiWKWebView/Basic/QiWKWebViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // QiWKWebViewController.h 3 | // QiWKWebView 4 | // 5 | // Created by wangyongwang on 2019/10/8. 6 | // Copyright © 2019 QiShare. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface QiWKWebViewController : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /QiWKWebView/Basic/QiWKWebViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // QiWKWebViewController.m 3 | // QiWKWebView 4 | // 5 | // Created by wangyongwang on 2019/10/8. 6 | // Copyright © 2019 QiShare. All rights reserved. 7 | // 8 | 9 | #import "QiWKWebViewController.h" 10 | #import 11 | #import "QiWKDetailViewController.h" 12 | 13 | @interface QiWKWebViewController () 14 | 15 | @property (nonatomic, strong) WKWebView *webView; 16 | 17 | @end 18 | 19 | @implementation QiWKWebViewController 20 | 21 | - (void)loadView { 22 | 23 | WKWebViewConfiguration *webConfiguration = [WKWebViewConfiguration new]; 24 | webConfiguration.dataDetectorTypes = WKDataDetectorTypePhoneNumber; 25 | _webView = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds configuration:webConfiguration]; 26 | _webView.backgroundColor = [UIColor whiteColor]; 27 | // 允许左滑右滑手势 28 | _webView.allowsBackForwardNavigationGestures = YES; 29 | self.view = _webView; 30 | } 31 | 32 | - (void)viewDidLoad { 33 | [super viewDidLoad]; 34 | 35 | [self setupUI]; 36 | } 37 | 38 | 39 | #pragma mark - Private Functions 40 | 41 | - (void)setupUI { 42 | 43 | self.navigationController.navigationBar.translucent = YES; 44 | self.title = @"WKWebView基本使用"; 45 | UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithTitle:@"WKBack" style:UIBarButtonItemStylePlain target:self action:@selector(leftItemClicked:)]; 46 | self.navigationItem.leftBarButtonItem = backItem; 47 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"更多" style:UIBarButtonItemStylePlain target:self action:@selector(moreItemClicked:)]; 48 | 49 | CGFloat toolBarH = 44.0; 50 | UIToolbar *toolBar = [[UIToolbar alloc] init]; 51 | toolBar.barTintColor = [UIColor lightGrayColor]; 52 | toolBar.frame = (CGRect){.0, CGRectGetHeight(self.view.frame) - toolBarH - [[UIApplication sharedApplication].windows firstObject].safeAreaInsets.bottom, CGRectGetWidth(self.view.frame), toolBarH}; 53 | [self.view addSubview:toolBar]; 54 | 55 | UIBarButtonItem *forwardItem = [[UIBarButtonItem alloc] initWithTitle:@"forward" style:UIBarButtonItemStyleDone target:self action:@selector(forwardButtonClicked:)]; 56 | UIBarButtonItem *backwardItem = [[UIBarButtonItem alloc] initWithTitle:@"backward" style:UIBarButtonItemStyleDone target:self action:@selector(backwardButtonClicked:)]; 57 | UIBarButtonItem *refreshItem = [[UIBarButtonItem alloc] initWithTitle:@"refresh" style:UIBarButtonItemStyleDone target:self action:@selector(backwardButtonClicked:)]; 58 | UIBarButtonItem *backforwardListItem = [[UIBarButtonItem alloc] initWithTitle:@"List" style:UIBarButtonItemStyleDone target:self action:@selector(backforwardListItemClicked:)]; 59 | UIBarButtonItem *snapItem = [[UIBarButtonItem alloc] initWithTitle:@"snap" style:UIBarButtonItemStyleDone target:self action:@selector(snapItemClicked:)]; 60 | 61 | toolBar.items = @[backwardItem,forwardItem,refreshItem, backforwardListItem, snapItem]; 62 | 63 | NSString *urlStr = @"https://www.so.com"; 64 | NSURL *url = [NSURL URLWithString:urlStr]; 65 | NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; 66 | [_webView loadRequest:request]; 67 | } 68 | 69 | 70 | #pragma mark - Actions 71 | 72 | - (void)leftItemClicked:(UIButton *)sender { 73 | 74 | if ([_webView canGoBack]) { 75 | [_webView goBack]; 76 | } else { 77 | [self.navigationController popViewControllerAnimated:YES]; 78 | } 79 | } 80 | 81 | 82 | - (void)forwardButtonClicked:(UIButton *)sender { 83 | 84 | if ([_webView canGoForward]) { 85 | [_webView goForward]; 86 | } 87 | } 88 | 89 | 90 | - (void)backwardButtonClicked:(UIButton *)sender { 91 | 92 | if ([_webView canGoBack]) { 93 | [_webView goBack]; 94 | } 95 | } 96 | 97 | 98 | - (void)refreshButtonClicked:(UIButton *)sender { 99 | 100 | [_webView reload]; 101 | } 102 | 103 | 104 | - (void)backforwardListItemClicked:(UIBarButtonItem *) sender { 105 | 106 | NSLog(@"%s", __FUNCTION__); 107 | if (_webView.backForwardList.forwardList.count > 0) { 108 | NSLog(@"forwardItem"); 109 | NSLog(@"title:%@", _webView.backForwardList.forwardItem.title); 110 | NSLog(@"URL:%@", _webView.backForwardList.forwardItem.URL); 111 | } 112 | if (_webView.backForwardList.backList.count > 0) { 113 | NSLog(@"backwardItem"); 114 | NSLog(@"title:%@", _webView.backForwardList.backItem.title); 115 | NSLog(@"URL:%@", _webView.backForwardList.backItem.URL); 116 | } 117 | } 118 | 119 | - (void)snapItemClicked:(UIBarButtonItem *)sender { 120 | 121 | WKSnapshotConfiguration *snapConfig = [[WKSnapshotConfiguration alloc] init]; 122 | [_webView takeSnapshotWithConfiguration:snapConfig completionHandler:^(UIImage * _Nullable snapshotImage, NSError * _Nullable error) { 123 | if (!error) { 124 | NSLog(@"%@", snapshotImage); 125 | UIImageWriteToSavedPhotosAlbum(snapshotImage, self, @selector(image:didFinishSavingWithError:contextInfo:), nil); 126 | } else { 127 | NSLog(@"error:%@", error); 128 | } 129 | }]; 130 | } 131 | 132 | - (void)moreItemClicked:(UIBarButtonItem *)sender { 133 | 134 | QiWKDetailViewController *detailVC = [QiWKDetailViewController new]; 135 | [self.navigationController pushViewController:detailVC animated:YES]; 136 | } 137 | 138 | -(void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { 139 | 140 | NSString *msg = nil; 141 | if(error){ 142 | msg = @"保存图片失败" ; 143 | }else{ 144 | msg = @"保存图片成功" ; 145 | } 146 | NSLog(@"%@", msg); 147 | } 148 | 149 | @end 150 | -------------------------------------------------------------------------------- /QiWKWebView/Custom/QiContentRule.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QiWKWebView 6 | 7 | 8 | 测试加载支持https的http链接的图片http://upload.jianshu.io/collections/images/1673367/8.png 9 |
10 | 11 |
12 | 测试block图片加载https://upload.jianshu.io/users/upload_avatars/2628633/c6a17aeb-04be-4862-9b2d-01db2a3dd16c.png 13 |
14 | 15 |
16 | 测试block图片 图片加载失败 17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /QiWKWebView/Custom/QiCustomResource.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QiWKWebView 6 | 7 | 8 | QiLocalCustomResource 9 |
10 | 从手机端获取图片 11 | 12 | 13 | -------------------------------------------------------------------------------- /QiWKWebView/Custom/QiCustomSchemeHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // QiCustomSchemeHandler.h 3 | // QiWKWebView 4 | // 5 | // Created by wangyongwang on 2019/10/23. 6 | // Copyright © 2019 QiShare. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | typedef void(^QiImageDataBlock)(NSData *data, NSURLResponse *response); 15 | 16 | @interface QiCustomSchemeHandler : NSObject 17 | 18 | @property (nonatomic, strong) UIImagePickerController *imagePickerController; 19 | //! 从哪个控制器过来 20 | @property (nonatomic, strong) UIViewController *sourceViewController; 21 | //! 图片数据回调 22 | @property (nonatomic, copy) QiImageDataBlock imageDataBlock; 23 | 24 | @end 25 | 26 | NS_ASSUME_NONNULL_END 27 | -------------------------------------------------------------------------------- /QiWKWebView/Custom/QiCustomSchemeHandler.m: -------------------------------------------------------------------------------- 1 | // 2 | // QiCustomSchemeHandler.m 3 | // QiWKWebView 4 | // 5 | // Created by wangyongwang on 2019/10/23. 6 | // Copyright © 2019 QiShare. All rights reserved. 7 | // 8 | 9 | #import "QiCustomSchemeHandler.h" 10 | #import 11 | 12 | @interface QiCustomSchemeHandler () 13 | 14 | @end 15 | 16 | @implementation QiCustomSchemeHandler 17 | 18 | - (void)webView:(WKWebView *)webView startURLSchemeTask:(id)urlSchemeTask { 19 | 20 | NSLog(@"%@", urlSchemeTask); 21 | NSLog(@"request:%@", urlSchemeTask.request); 22 | NSLog(@"absoluteString:%@", urlSchemeTask.request.URL.absoluteString); 23 | if ([urlSchemeTask.request.URL.absoluteString hasPrefix:@"qilocal://"]) { // qiLocal 24 | dispatch_async(dispatch_get_main_queue(), ^{ 25 | self.imageDataBlock = ^(NSData * _Nonnull data, NSURLResponse * _Nonnull response) { 26 | NSLog(@"response信息:%@", response); 27 | [urlSchemeTask didReceiveResponse:response]; 28 | [urlSchemeTask didReceiveData:data]; 29 | [urlSchemeTask didFinish]; 30 | }; 31 | UIImagePickerController *imagePicker = [UIImagePickerController new]; 32 | imagePicker.delegate = self.sourceViewController; 33 | imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; 34 | [self.sourceViewController showViewController:imagePicker sender:nil]; 35 | self.imagePickerController = imagePicker; 36 | }); 37 | } 38 | } 39 | 40 | - (void)webView:(WKWebView *)webView stopURLSchemeTask:(id)urlSchemeTask { 41 | 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /QiWKWebView/Custom/QiCustomWKWebViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // QiCustomWKWebViewController.h 3 | // QiWKWebView 4 | // 5 | // Created by wangyongwang on 2019/10/23. 6 | // Copyright © 2019 QiShare. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface QiCustomWKWebViewController : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /QiWKWebView/Custom/QiCustomWKWebViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // QiCustomWKWebViewController.m 3 | // QiWKWebView 4 | // 5 | // Created by wangyongwang on 2019/10/23. 6 | // Copyright © 2019 QiShare. All rights reserved. 7 | // 8 | 9 | #import "QiCustomWKWebViewController.h" 10 | #import 11 | #import "QiCustomSchemeHandler.h" 12 | 13 | @interface QiCustomWKWebViewController () < WKNavigationDelegate> 14 | 15 | @property (nonatomic, strong) WKWebView *webView; 16 | @property (nonatomic, strong) QiCustomSchemeHandler *schemeHandler; 17 | 18 | @end 19 | 20 | @implementation QiCustomWKWebViewController 21 | 22 | - (void)loadView { 23 | 24 | WKWebViewConfiguration *webConfig = [WKWebViewConfiguration new]; 25 | _schemeHandler = [QiCustomSchemeHandler new]; 26 | // [webConfig setURLSchemeHandler:_schemeHandler forURLScheme:@"qiLocal"]; 27 | // https qilocal 28 | // Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: ''https' is a URL scheme that WKWebView handles natively' 29 | 30 | _webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:webConfig]; 31 | _webView.allowsBackForwardNavigationGestures = YES; 32 | _webView.backgroundColor = [UIColor whiteColor]; 33 | self.view = _webView; 34 | } 35 | 36 | - (void)viewDidLoad { 37 | [super viewDidLoad]; 38 | 39 | self.edgesForExtendedLayout = UIRectEdgeNone; 40 | self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStyleDone target:self action:@selector(leftItemClicked:)]; 41 | 42 | _schemeHandler.sourceViewController = self; 43 | // [self configMakeHttps]; 44 | // [self configBlockURL]; 45 | // [self configBlockLoadSomeResource]; 46 | 47 | _webView.navigationDelegate = self; 48 | [self loadCustomResourceHtml]; 49 | 50 | // [self loadContentRuleHtml]; 51 | // [self loadWebContent]; 52 | // [self loadCustomResourceHtml]; 53 | } 54 | 55 | //! 加载自定义资源 56 | - (void)loadCustomResourceHtml { 57 | 58 | self.title = @"loadCustomResource"; 59 | [_webView loadFileURL:[[NSBundle mainBundle] URLForResource:@"QiCustomResource" withExtension:@"html"] allowingReadAccessToURL:[[NSBundle mainBundle] bundleURL]]; 60 | } 61 | 62 | //! 加载网络内容 63 | - (void)loadWebContent { 64 | 65 | self.title = @"WKContentRuleList"; 66 | // [_webView loadRequest:[[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://www.so.com"]]]; 67 | [_webView loadRequest: [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.jianshu.com/u/3db23baa08c7"]]]; 68 | } 69 | 70 | //! 加载ContentRuleList测试内容 71 | - (void)loadContentRuleHtml { 72 | 73 | self.title = @"WKContentRuleList"; 74 | [_webView loadFileURL:[[NSBundle mainBundle] URLForResource:@"QiContentRule" withExtension:@"html"] allowingReadAccessToURL:[[NSBundle mainBundle] bundleURL]]; 75 | } 76 | 77 | //! 配置阻塞某些资源的加载 78 | - (void)configBlockLoadSomeResource { 79 | 80 | NSArray *jsonArr = 81 | @[ 82 | // block资源 83 | @{ 84 | @"trigger": @{ 85 | @"url-filter": @".*", 86 | // @"resource-type": @[@"image", @"style-sheet", @"font", @"script", @"document", @"media", @"popup"], 87 | @"resource-type": @[@"image"], 88 | // @"unless-domain": @[@"www.jianshu.com"], 89 | @"if-domain": @[@"www.jianshu.com"], 90 | }, 91 | @"action": @{ 92 | //block:Stops loading of the resource. If the resource was cached, the cache is ignored. 93 | // 停止加载资源。 如果已缓存资源,则忽略缓存。 94 | @"type": @"block" 95 | } 96 | } 97 | ]; 98 | [self compileContentRuleWithJsonArray:jsonArr]; 99 | } 100 | 101 | - (void)configBlockURL { 102 | 103 | NSArray *jsonArr = 104 | @[ 105 | @{ 106 | @"trigger": @{ 107 | // 配置特定的URL 也可以通过正则匹配符合其他条件的URL 108 | @"url-filter": @"(https://upload.jianshu.io/users/upload_avatars/2628633/c6a17aeb-04be-4862-9b2d-01db2a3dd16c.png)", 109 | 110 | }, 111 | @"action": @{ 112 | @"type": @"block" 113 | } 114 | }, 115 | // 下边字典 笔者又测试了一次make-https 把http 转为https 这部分内容不是block的内容 116 | @{ 117 | @"trigger": @{ 118 | @"url-filter": @".*" 119 | }, 120 | @"action": @{ 121 | @"type": @"make-https" 122 | } 123 | }, 124 | ]; 125 | [self compileContentRuleWithJsonArray:jsonArr]; 126 | } 127 | 128 | - (void)configMakeHttps { 129 | 130 | NSArray *jsonArr = 131 | @[@{ 132 | @"trigger": @{ 133 | @"url-filter": @".*" 134 | }, 135 | @"action": @{ 136 | @"type": @"make-https" 137 | } 138 | }, 139 | ]; 140 | 141 | [self compileContentRuleWithJsonArray:jsonArr]; 142 | } 143 | 144 | - (void)compileContentRuleWithJsonArray:(NSArray *)jsonArr { 145 | 146 | NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonArr options:NSJSONWritingPrettyPrinted error:nil]; 147 | NSString *jsonStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; 148 | 149 | [[WKContentRuleListStore defaultStore] compileContentRuleListForIdentifier:@"ContentBlockingRules" 150 | encodedContentRuleList:jsonStr 151 | completionHandler:^(WKContentRuleList *ruleList, NSError *err) { 152 | if (ruleList) { 153 | [self.webView.configuration.userContentController addContentRuleList:ruleList]; 154 | NSLog(@"编译的ruleList:%@", ruleList); 155 | } else { 156 | NSLog(@"编译的ruleList为空,错误信息:%@", err); 157 | } 158 | }]; 159 | } 160 | 161 | 162 | - (void)configContentRuleList { 163 | 164 | NSArray *jsonArr = 165 | @[@{ 166 | // url-filter:specifies a pattern to match the URL against. 167 | // 指定一个正则表达式或匹配URL 168 | // @"url-filter": @".*" 匹配加载过的所有URL 169 | // 匹配所有带有零次或多次出现的点的字符串。 使用此语法来匹配每个URL。 170 | 171 | // .* make-https 对于所有的url的请求进行https的处理 172 | @"trigger": @{ 173 | @"url-filter": @".*" 174 | // @"url-filter": @"https://upload.jianshu.io/collections/images/1673367/8.png?imageMogr2/auto-orient/strip" 175 | }, 176 | @"action": @{ 177 | // make-https:Changes a URL from http to https. URLs with a specified (nondefault) port and links using other protocols are unaffected. 178 | // make-https:将URL从http更改为https。 具有指定(非默认)端口的URL和使用其他协议的链接不受影响。 179 | // 如果对应的httpsURL可以正常加载,则会加载https的内容,否则仍然会加载失败。 180 | @"type": @"make-https" 181 | } 182 | }, 183 | 184 | @{ 185 | // 针对url中包含的字符串或具体的url选择是否阻塞加载 186 | @"trigger": @{ 187 | // @"url-filter": @"(2628633)" 188 | // @"url-filter": @"jianshu", 189 | @"url-filter": @"(2628633)", 190 | }, 191 | @"action": @{ 192 | @"type": @"block" 193 | } 194 | }, 195 | 196 | // block资源 197 | @{ 198 | @"trigger": @{ 199 | @"url-filter": @".*", 200 | // @"resource-type": @[@"image", @"style-sheet", @"font", @"script", @"document", @"media", @"popup"], 201 | @"resource-type": @[@"image"], 202 | // @"unless-domain": @[@"www.jianshu.com"], 203 | @"if-domain": @[@"www.jianshu.com"], 204 | }, 205 | @"action": @{ 206 | //block:Stops loading of the resource. If the resource was cached, the cache is ignored. 207 | // 停止加载资源。 如果已缓存资源,则忽略缓存。 208 | @"type": @"block" 209 | } 210 | }, 211 | 212 | 213 | ]; 214 | 215 | NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonArr options:NSJSONWritingPrettyPrinted error:nil]; 216 | NSString *jsonStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; 217 | 218 | NSLog(@"%s", __FUNCTION__); 219 | // Compiles a new rules list and adds it to the store. 220 | // 编译新的rules list 并且添加到WKContentRuleListStore中 221 | [[WKContentRuleListStore defaultStore] compileContentRuleListForIdentifier:@"ContentBlockingRules" 222 | encodedContentRuleList:jsonStr 223 | completionHandler:^(WKContentRuleList *ruleList, NSError *err) { 224 | if (ruleList) { 225 | [self.webView.configuration.userContentController addContentRuleList:ruleList]; 226 | NSLog(@"编译的ruleList:%@", ruleList); 227 | } else { 228 | NSLog(@"编译的ruleList为空,错误信息:%@", err); 229 | } 230 | }]; 231 | 232 | // 查询WKContentRuleList 233 | [[WKContentRuleListStore defaultStore] lookUpContentRuleListForIdentifier:@"ContentBlockingRules" 234 | completionHandler:^(WKContentRuleList *ruleList, NSError *error) { 235 | if (ruleList) { 236 | NSLog(@"查询ruleList:%@", ruleList); 237 | } else { 238 | NSLog(@"查询ruleList错误信息:%@", error); 239 | } 240 | }]; 241 | } 242 | 243 | #pragma mark - Actions 244 | 245 | - (void)leftItemClicked:(UIBarButtonItem *)sender { 246 | 247 | if ([self.webView canGoBack]) { 248 | [self.webView goBack]; 249 | } else { 250 | [self.navigationController popViewControllerAnimated:YES]; 251 | } 252 | } 253 | 254 | #pragma mark - Delegate 255 | 256 | - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { 257 | 258 | [picker dismissViewControllerAnimated:YES completion:nil]; 259 | UIImage *image = info[UIImagePickerControllerOriginalImage]; 260 | // NSData *data = UIImagePNGRepresentation(image); 261 | // 使用png方式压缩的图片 显示可能异常 可能是因为图片太大了 262 | NSData *data = UIImageJPEGRepresentation(image, 0.5); 263 | NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[NSURL URLWithString:@"qiLocalImage://"] MIMEType:@"image/jpeg" expectedContentLength:data.length textEncodingName:NULL]; 264 | if (self.schemeHandler.imageDataBlock) { 265 | self.schemeHandler.imageDataBlock(data, response); 266 | } 267 | } 268 | 269 | - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { 270 | 271 | [picker dismissViewControllerAnimated:YES completion:nil]; 272 | } 273 | 274 | - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { 275 | 276 | decisionHandler(WKNavigationActionPolicyAllow); 277 | } 278 | 279 | 280 | 281 | @end 282 | -------------------------------------------------------------------------------- /QiWKWebView/Custom/QiWKScriptViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // QiWKScriptViewController.h 3 | // QiWKWebView 4 | // 5 | // Created by wangyongwang on 2019/11/4. 6 | // Copyright © 2019 QiShare. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface QiWKScriptViewController : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /QiWKWebView/Custom/QiWKScriptViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // QiWKScriptViewController.m 3 | // QiWKWebView 4 | // 5 | // Created by wangyongwang on 2019/11/4. 6 | // Copyright © 2019 QiShare. All rights reserved. 7 | // 8 | 9 | #import "QiWKScriptViewController.h" 10 | #import 11 | 12 | @interface QiWKScriptViewController () 13 | 14 | @property (nonatomic, strong) WKWebView *webView; 15 | 16 | @end 17 | 18 | @implementation QiWKScriptViewController 19 | 20 | - (void)loadView { 21 | 22 | WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; 23 | _webView = [[WKWebView alloc] initWithFrame: [UIScreen mainScreen].bounds configuration:config]; 24 | self.view = _webView; 25 | } 26 | 27 | - (void)viewDidLoad { 28 | [super viewDidLoad]; 29 | 30 | self.view.backgroundColor = [UIColor whiteColor]; 31 | [self setupUI]; 32 | } 33 | 34 | - (void)setupUI { 35 | 36 | NSURL *url = [NSURL URLWithString:@"https://en.wikipedia.org/wiki/Qihoo_360"]; 37 | // url = [NSURL URLWithString:@"https://www.so.com"]; 38 | // url = [NSURL URLWithString:@"https://m.baike.so.com/doc/824561-872078.html"]; //不能正常加载 除非配置了ATS 39 | // 手机端使用 40 | // url =[NSURL URLWithString:@"https://m.baike.so.com/doc/824561-872078.html"]; 41 | // 手机端使用 42 | // url = [NSURL URLWithString:@"https://en.m.wikipedia.org/wiki/Qihoo_360"]; 43 | 44 | NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; 45 | _webView.navigationDelegate = self; 46 | _webView.UIDelegate = self; 47 | [_webView loadRequest:request]; 48 | } 49 | 50 | - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView { 51 | 52 | [webView reload]; 53 | NSLog(@"进程终止"); 54 | } 55 | 56 | //- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { 57 | // if (navigationAction.targetFrame) { 58 | // 59 | // } else { 60 | // [webView loadRequest:navigationAction.request]; 61 | // } 62 | // decisionHandler(WKNavigationActionPolicyAllow); 63 | // /* 64 | // (lldb) po navigationAction.sourceFrame 65 | // nil 66 | // po navigationAction.targetFrame 67 | // (lldb) po navigationAction.sourceFrame 68 | // nil 69 | // (lldb) po navigationAction.sourceFrame.request 70 | // nil 71 | // */ 72 | //} 73 | // 74 | //- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation { 75 | // 76 | //} 77 | // 78 | //- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler { 79 | // 80 | // NSLog(@"%@", challenge.protectionSpace.serverTrust); 81 | // NSURLCredential *trustCredential = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust]; 82 | // completionHandler(NSURLSessionAuthChallengeUseCredential, trustCredential); 83 | //} 84 | // 85 | // 86 | // 87 | //- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures { 88 | // 89 | // WKFrameInfo *frameInfo = navigationAction.targetFrame; 90 | // if (!frameInfo.isMainFrame) { 91 | // [webView loadRequest:navigationAction.request]; 92 | // } 93 | // 94 | // NSLog(@"%@", webView.URL); 95 | // NSLog(@"%@", navigationAction.targetFrame); 96 | // return nil; 97 | //} 98 | 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /QiWKWebView/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSAppTransportSecurity 6 | 7 | NSAllowsArbitraryLoads 8 | 9 | 10 | NSPhotoLibraryAddUsageDescription 11 | 为了保存相片到相册,QiWKWebView需要访问您的相机 12 | NSPhotoLibraryUsageDescription 13 | 为了保存相片到相册,QiWKWebView需要访问您的相机 14 | CFBundleDevelopmentRegion 15 | $(DEVELOPMENT_LANGUAGE) 16 | CFBundleExecutable 17 | $(EXECUTABLE_NAME) 18 | CFBundleIdentifier 19 | $(PRODUCT_BUNDLE_IDENTIFIER) 20 | CFBundleInfoDictionaryVersion 21 | 6.0 22 | CFBundleName 23 | $(PRODUCT_NAME) 24 | CFBundlePackageType 25 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 26 | CFBundleShortVersionString 27 | 1.0 28 | CFBundleVersion 29 | 1 30 | LSRequiresIPhoneOS 31 | 32 | UIApplicationSceneManifest 33 | 34 | UIApplicationSupportsMultipleScenes 35 | 36 | UISceneConfigurations 37 | 38 | UIWindowSceneSessionRoleApplication 39 | 40 | 41 | UISceneConfigurationName 42 | Default Configuration 43 | UISceneDelegateClassName 44 | SceneDelegate 45 | UISceneStoryboardFile 46 | Main 47 | 48 | 49 | 50 | 51 | UILaunchStoryboardName 52 | LaunchScreen 53 | UIMainStoryboardFile 54 | Main 55 | UIRequiredDeviceCapabilities 56 | 57 | armv7 58 | 59 | UISupportedInterfaceOrientations 60 | 61 | UIInterfaceOrientationPortrait 62 | UIInterfaceOrientationLandscapeLeft 63 | UIInterfaceOrientationLandscapeRight 64 | 65 | UISupportedInterfaceOrientations~ipad 66 | 67 | UIInterfaceOrientationPortrait 68 | UIInterfaceOrientationPortraitUpsideDown 69 | UIInterfaceOrientationLandscapeLeft 70 | UIInterfaceOrientationLandscapeRight 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /QiWKWebView/SceneDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.h 3 | // QiWKWebView 4 | // 5 | // Created by wangyongwang on 2019/10/8. 6 | // Copyright © 2019 QiShare. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SceneDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow * window; 14 | 15 | @end 16 | 17 | -------------------------------------------------------------------------------- /QiWKWebView/SceneDelegate.m: -------------------------------------------------------------------------------- 1 | #import "SceneDelegate.h" 2 | #import "ViewController.h" 3 | 4 | @implementation SceneDelegate 5 | 6 | 7 | - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { 8 | 9 | if (@available(iOS 13.0, *)) { 10 | UIWindowScene *windowScene = [[UIWindowScene alloc] initWithSession:session connectionOptions:connectionOptions]; 11 | self.window = [[UIWindow alloc] initWithWindowScene:windowScene]; 12 | self.window.frame = windowScene.coordinateSpace.bounds; 13 | ViewController *vc = [ViewController new]; 14 | UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc]; 15 | self.window.rootViewController = nav; 16 | [self.window makeKeyAndVisible]; 17 | } 18 | } 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /QiWKWebView/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // QiWKWebView 4 | // 5 | // Created by wangyongwang on 2019/10/8. 6 | // Copyright © 2019 QiShare. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /QiWKWebView/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // QiWKWebView 4 | // 5 | // Created by wangyongwang on 2019/10/8. 6 | // Copyright © 2019 QiShare. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "QiWKWebViewController.h" 11 | #import "QiCustomWKWebViewController.h" 12 | #import "QiWKScriptViewController.h" 13 | 14 | @implementation ViewController 15 | 16 | - (void)viewDidLoad { 17 | [super viewDidLoad]; 18 | [self setupUI]; 19 | } 20 | 21 | - (void)setupUI { 22 | 23 | self.title = @"WKWebView"; 24 | self.view.backgroundColor = [UIColor whiteColor]; 25 | 26 | UIButton *wkBasicUseButton = [UIButton buttonWithType:UIButtonTypeCustom]; 27 | [wkBasicUseButton setTitle:@"WKWebView基础使用" forState:UIControlStateNormal]; 28 | wkBasicUseButton.backgroundColor = [UIColor grayColor]; 29 | [self.view addSubview:wkBasicUseButton]; 30 | [wkBasicUseButton sizeToFit]; 31 | wkBasicUseButton.center = self.view.center; 32 | [wkBasicUseButton addTarget:self action:@selector(wkBasicUseButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; 33 | 34 | UIButton *customWKWebViewButton = [UIButton buttonWithType:UIButtonTypeCustom]; 35 | [customWKWebViewButton setTitle:@"自定义WKWebView显示内容" forState:UIControlStateNormal]; 36 | customWKWebViewButton.backgroundColor = [UIColor grayColor]; 37 | [self.view addSubview:customWKWebViewButton]; 38 | [customWKWebViewButton sizeToFit]; 39 | customWKWebViewButton.center = (CGPoint){CGRectGetMidX(wkBasicUseButton.frame), CGRectGetMidY(wkBasicUseButton.frame) + 100.0}; 40 | [customWKWebViewButton addTarget:self action:@selector(customWKWebViewButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; 41 | 42 | UIButton *scriptButton = [UIButton buttonWithType:UIButtonTypeCustom]; 43 | [scriptButton setTitle:@"自定义WKWebView显示内容" forState:UIControlStateNormal]; 44 | scriptButton.backgroundColor = [UIColor grayColor]; 45 | // [self.view addSubview:scriptButton]; 46 | [scriptButton sizeToFit]; 47 | scriptButton.center = (CGPoint){CGRectGetMidX(wkBasicUseButton.frame), CGRectGetMidY(customWKWebViewButton.frame) + 100.0}; 48 | [scriptButton addTarget:self action:@selector(scriptButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; 49 | } 50 | 51 | - (void)scriptButtonClicked:(UIButton *)sender { 52 | 53 | QiWKScriptViewController *scriptVC = [QiWKScriptViewController new]; 54 | [self.navigationController pushViewController:scriptVC animated:YES]; 55 | } 56 | 57 | - (void)customWKWebViewButtonClicked:(UIButton *)sender { 58 | 59 | [self.navigationController pushViewController:[QiCustomWKWebViewController new] animated:YES]; 60 | } 61 | 62 | - (void)wkBasicUseButtonClicked:(UIButton *)sender { 63 | 64 | [self.navigationController pushViewController:[QiWKWebViewController new] animated:YES]; 65 | } 66 | @end 67 | -------------------------------------------------------------------------------- /QiWKWebView/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // QiWKWebView 4 | // 5 | // Created by wangyongwang on 2019/10/8. 6 | // Copyright © 2019 QiShare. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | NSString * appDelegateClassName; 14 | @autoreleasepool { 15 | // Setup code that might create autoreleased objects goes here. 16 | appDelegateClassName = NSStringFromClass([AppDelegate class]); 17 | } 18 | return UIApplicationMain(argc, argv, nil, appDelegateClassName); 19 | } 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QiWKWebView 2 | [iOS WKWebView的基本使用](https://juejin.im/post/5da4363ef265da5bb065e357) 3 | 4 | 自定义WKWebView显示内容(一) 5 | --------------------------------------------------------------------------------