├── .gitignore
├── README.md
├── WeAppTongCeng.xcodeproj
└── project.pbxproj
├── WeAppTongCeng
├── AppDelegate.h
├── AppDelegate.m
├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Info.plist
├── LVTongCeng
│ ├── LVApiHandleDelegate-Protocol.h
│ ├── LVApiHandler.h
│ ├── LVApiHandler.m
│ ├── LVContainerView.h
│ ├── LVContainerView.m
│ ├── LVTongCengWebDelegate-Protocol.h
│ ├── LVTongCengWebMgr.h
│ ├── LVTongCengWebMgr.m
│ ├── LVTongCengWebView.h
│ ├── LVTongCengWebView.m
│ ├── LVWeakProxy.h
│ ├── LVWeakProxy.m
│ ├── LVWebViewBridge.h
│ ├── LVWebViewBridge.m
│ └── YYWAWebView.cpp
├── ViewController.h
├── ViewController.m
├── main.m
└── test
│ ├── LVTongCengWebController.h
│ ├── LVTongCengWebController.m
│ ├── LVWKWebController.h
│ ├── LVWKWebController.m
│ ├── LVWebViewBridge
│ ├── LVBridge.h
│ └── LVTongCengWebManager.h
│ └── tongceng.html
├── WeAppTongCengTests
├── Info.plist
└── WeAppTongCengTests.m
└── WeAppTongCengUITests
├── Info.plist
└── WeAppTongCengUITests.m
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS X
2 | .DS_Store
3 |
4 | # Xcode
5 | build/
6 | *.pbxuser
7 | !default.pbxuser
8 | *.mode1v3
9 | !default.mode1v3
10 | *.mode2v3
11 | !default.mode2v3
12 | *.perspectivev3
13 | !default.perspectivev3
14 | xcuserdata/
15 | *.xccheckout
16 | profile
17 | *.moved-aside
18 | DerivedData
19 | *.hmap
20 | *.ipa
21 | .idea/
22 | *.xccheckout
23 | *.xcworkspace
24 |
25 | #CocoaPods
26 | Pods
27 | Manifest.lock
28 | Podfile.lock
29 | # We recommend against adding the Pods directory to your .gitignore. However
30 | # you should judge for yourself, the pros and cons are mentioned at:
31 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
32 | #
33 | # Note: if you ignore the Pods directory, make sure to uncomment
34 | # `pod install` in .travis.yml
35 | #
36 | # Pods/
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | > 自微信小程序火了后, 个大头部厂商也纷纷效仿, 给自己的客户端提供了小程序框架支持. 然而小程序框架为了提升小程序页面的极致用户体验, 做了**同层渲染**.
2 |
3 | **抛砖引玉:**
4 |
5 | **我们今天的目标就是: 从0到1实现iOS端`WKWebView`同层渲染, 文章末尾有DEMO演示, 也有源码地址.**
6 |
7 | 
8 |
9 |
10 |
11 |
12 |
13 | # 同层渲染原理
14 |
15 | 「同层渲染」就是把原生组件绘制在 `WebView` 所渲染的页面中,与其他 `HTML` 控件在同一层级,效果如下图所示:
16 | 
17 |
18 | 这里我给大家找到三篇比较官方的文章, 建议跳过看总结:
19 |
20 | - 腾讯 [微信小程序同层渲染原理剖析](https://developers.weixin.qq.com/community/develop/article/doc/000c4e433707c072c1793e56f5c813?page=1)
21 | - 百度[【走进小程序原理】揭秘组件同层渲染](https://blog.csdn.net/Smartprogram/article/details/108124407) **(推荐)**
22 | - 阿里 [亿级用户高稳定性视频播放器养成计划|618淘系前端技术分享](https://mp.weixin.qq.com/s/jgsG-XrAKV6AHSrUCRhKtQ)
23 |
24 |
25 | > 总结
26 | >
27 | > 这些文章只阐述了基本实现思路, 并没有教你怎么实现, 然并卵.
28 | >
29 | > 看完之后各大技术论坛的“同层渲染原理分析”的你, 还是实现不了.
30 | > **下面我们一起来实现一个.**
31 |
32 |
33 |
34 | # 实现同层渲染
35 |
36 | ## 1. 我们在前端H5页面上创建一个需要生成原生组件的`DOM`节点.
37 |
38 | ```html
39 |
42 |
43 |
50 | ```
51 |
52 | ## 2. 前端会把原生组件类型如`cid`、`position`等信息通过`window.webkit.messageHandlers.handle.postMessage`发送给iOS端.
53 |
54 | ```javascript
55 |
109 | ```
110 |
111 | ## 3. iOS端WKWebView消息代理接收到前端发来的消息
112 |
113 | ```objective-c
114 | - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
115 | // 收到前端的消息
116 | // message.name: handle
117 | // message.body: {"api":"insertInput","args":{"cid":"1","position":{"top":30,"width":200,"left":87.5,"height":40}}}
118 | }
119 | ```
120 |
121 | ## 4. iOS端可以通过消息中的`cid`匹配查找相应`WKChildScrollView`,并将原生组件挂载到该节点上作为其子View.
122 |
123 | 
124 |
125 |
126 |
127 | ## 5. 最后我们发现WKWebView中插入的原生组件是无法响应交互事件的,需要特殊处理.
128 |
129 | 这里我们需要处理两件事,一是屏蔽`WKContentView`手势拦截事件响应链的传递,让事件可以传递到原生组件中,命令如下:
130 |
131 | ```objective-c
132 | @implementation LVTongCengWebView
133 |
134 | - (void)_handleWKContentGestrues {
135 | UIScrollView *webViewScrollView = self.scrollView;
136 | if ([webViewScrollView isKindOfClass:NSClassFromString(@"WKScrollView")]) {
137 | UIView *_WKContentView = webViewScrollView.subviews.firstObject;
138 | if (![_WKContentView isKindOfClass:NSClassFromString(@"WKContentView")]) return;
139 | NSArray *gestrues = _WKContentView.gestureRecognizers;
140 | for (UIGestureRecognizer *gesture in gestrues) {
141 | gesture.cancelsTouchesInView = NO;
142 | gesture.delaysTouchesBegan = NO;
143 | gesture.delaysTouchesEnded = NO;
144 | }
145 | }
146 | }
147 |
148 | @end
149 | ```
150 |
151 | 二是重写iOS端`原生组件`容器`LVContainerView`协议检测方法`-conformsToProtocol:`,目的是绕过`WKNativelyInteractible`协议检测,从而在点击WKWebView的时候,容器`LVContainerView`及其子view(原生组件)可以正常进行事件响应。
152 |
153 | ```objective-c
154 | @implementation LVContainerView
155 |
156 | - (BOOL)conformsToProtocol:(Protocol *)aProtocol {
157 | if (aProtocol == NSProtocolFromString(@"WKNativelyInteractible")) {
158 | return YES;
159 | }
160 | return [super conformsToProtocol:aProtocol];
161 | }
162 |
163 | @end
164 | ```
165 |
166 |
167 |
168 | 到这里,经过前面这些步骤,我们就实现了iOS端`WKWebView`的`同层渲染`,下面让我们来看看实现效果:
169 |
170 | 1. 我们可以看到原生组件`UITextField`、`UITextView`响应聚焦输入,`UIButton`可以点击变颜色,实现了正常交互;
171 | 2. H5蒙层可以遮挡住`原生组件`,解决了`WKWebView`内嵌原生组件的层级限制问题,完美体现了`同层`的含义。
172 |
173 |
174 |

175 |
176 |
177 | **Talk is cheap. Show me the code.**
178 | DEMO地址: [https://github.com/lionvoom/WeAppTongCeng](https://github.com/lionvoom/WeAppTongCeng)
179 |
180 | **极客时间-每日一课**
181 | [iOS小程序同层渲染到底怎么实现?](https://time.geekbang.org/dailylesson/detail/100075719)
182 |
--------------------------------------------------------------------------------
/WeAppTongCeng.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 090C2CF925FA0F4100330C86 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 090C2CF825FA0F4100330C86 /* AppDelegate.m */; };
11 | 090C2CFF25FA0F4100330C86 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 090C2CFE25FA0F4100330C86 /* ViewController.m */; };
12 | 090C2D0225FA0F4100330C86 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 090C2D0025FA0F4100330C86 /* Main.storyboard */; };
13 | 090C2D0425FA0F4400330C86 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 090C2D0325FA0F4400330C86 /* Assets.xcassets */; };
14 | 090C2D0725FA0F4400330C86 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 090C2D0525FA0F4400330C86 /* LaunchScreen.storyboard */; };
15 | 090C2D0A25FA0F4400330C86 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 090C2D0925FA0F4400330C86 /* main.m */; };
16 | 090C2D1425FA0F4400330C86 /* WeAppTongCengTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 090C2D1325FA0F4400330C86 /* WeAppTongCengTests.m */; };
17 | 090C2D1F25FA0F4400330C86 /* WeAppTongCengUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 090C2D1E25FA0F4400330C86 /* WeAppTongCengUITests.m */; };
18 | 090C2D3325FA108100330C86 /* LVTongCengWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 090C2D3225FA108100330C86 /* LVTongCengWebView.m */; };
19 | 090C2D5625FB1CD800330C86 /* LVTongCengWebController.m in Sources */ = {isa = PBXBuildFile; fileRef = 090C2D5525FB1CD800330C86 /* LVTongCengWebController.m */; };
20 | 090C2D7025FB1E0400330C86 /* LVContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 090C2D6F25FB1E0400330C86 /* LVContainerView.m */; };
21 | 090C2D8625FB793000330C86 /* tongceng.html in Resources */ = {isa = PBXBuildFile; fileRef = 090C2D8525FB793000330C86 /* tongceng.html */; };
22 | 0936DCC525FF32AD007A65EB /* LVWeakProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 0936DCC425FF32AD007A65EB /* LVWeakProxy.m */; };
23 | 094273D92600919100B26EB8 /* LVWKWebController.m in Sources */ = {isa = PBXBuildFile; fileRef = 094273D82600919100B26EB8 /* LVWKWebController.m */; };
24 | 094273E42600967600B26EB8 /* LVWebViewBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 094273E32600967600B26EB8 /* LVWebViewBridge.m */; };
25 | 094273F3260096BD00B26EB8 /* LVApiHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 094273F2260096BD00B26EB8 /* LVApiHandler.m */; };
26 | 094273F92600993200B26EB8 /* LVTongCengWebMgr.m in Sources */ = {isa = PBXBuildFile; fileRef = 094273F82600993200B26EB8 /* LVTongCengWebMgr.m */; };
27 | /* End PBXBuildFile section */
28 |
29 | /* Begin PBXContainerItemProxy section */
30 | 090C2D1025FA0F4400330C86 /* PBXContainerItemProxy */ = {
31 | isa = PBXContainerItemProxy;
32 | containerPortal = 090C2CEC25FA0F4100330C86 /* Project object */;
33 | proxyType = 1;
34 | remoteGlobalIDString = 090C2CF325FA0F4100330C86;
35 | remoteInfo = WeAppTongCeng;
36 | };
37 | 090C2D1B25FA0F4400330C86 /* PBXContainerItemProxy */ = {
38 | isa = PBXContainerItemProxy;
39 | containerPortal = 090C2CEC25FA0F4100330C86 /* Project object */;
40 | proxyType = 1;
41 | remoteGlobalIDString = 090C2CF325FA0F4100330C86;
42 | remoteInfo = WeAppTongCeng;
43 | };
44 | /* End PBXContainerItemProxy section */
45 |
46 | /* Begin PBXFileReference section */
47 | 090C2CF425FA0F4100330C86 /* WeAppTongCeng.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WeAppTongCeng.app; sourceTree = BUILT_PRODUCTS_DIR; };
48 | 090C2CF725FA0F4100330C86 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
49 | 090C2CF825FA0F4100330C86 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
50 | 090C2CFD25FA0F4100330C86 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
51 | 090C2CFE25FA0F4100330C86 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
52 | 090C2D0125FA0F4100330C86 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
53 | 090C2D0325FA0F4400330C86 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
54 | 090C2D0625FA0F4400330C86 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
55 | 090C2D0825FA0F4400330C86 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
56 | 090C2D0925FA0F4400330C86 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
57 | 090C2D0F25FA0F4400330C86 /* WeAppTongCengTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WeAppTongCengTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
58 | 090C2D1325FA0F4400330C86 /* WeAppTongCengTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WeAppTongCengTests.m; sourceTree = ""; };
59 | 090C2D1525FA0F4400330C86 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
60 | 090C2D1A25FA0F4400330C86 /* WeAppTongCengUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WeAppTongCengUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
61 | 090C2D1E25FA0F4400330C86 /* WeAppTongCengUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WeAppTongCengUITests.m; sourceTree = ""; };
62 | 090C2D2025FA0F4400330C86 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
63 | 090C2D3125FA108100330C86 /* LVTongCengWebView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LVTongCengWebView.h; sourceTree = ""; };
64 | 090C2D3225FA108100330C86 /* LVTongCengWebView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LVTongCengWebView.m; sourceTree = ""; };
65 | 090C2D3825FA141700330C86 /* YYWAWebView.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = YYWAWebView.cpp; sourceTree = ""; };
66 | 090C2D5425FB1CD800330C86 /* LVTongCengWebController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LVTongCengWebController.h; sourceTree = ""; };
67 | 090C2D5525FB1CD800330C86 /* LVTongCengWebController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LVTongCengWebController.m; sourceTree = ""; };
68 | 090C2D6E25FB1E0400330C86 /* LVContainerView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LVContainerView.h; sourceTree = ""; };
69 | 090C2D6F25FB1E0400330C86 /* LVContainerView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LVContainerView.m; sourceTree = ""; };
70 | 090C2D8525FB793000330C86 /* tongceng.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = tongceng.html; sourceTree = ""; };
71 | 0936DCC325FF32AD007A65EB /* LVWeakProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LVWeakProxy.h; sourceTree = ""; };
72 | 0936DCC425FF32AD007A65EB /* LVWeakProxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LVWeakProxy.m; sourceTree = ""; };
73 | 094273D72600919100B26EB8 /* LVWKWebController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LVWKWebController.h; sourceTree = ""; };
74 | 094273D82600919100B26EB8 /* LVWKWebController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LVWKWebController.m; sourceTree = ""; };
75 | 094273E22600967600B26EB8 /* LVWebViewBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LVWebViewBridge.h; sourceTree = ""; };
76 | 094273E32600967600B26EB8 /* LVWebViewBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LVWebViewBridge.m; sourceTree = ""; };
77 | 094273F1260096BD00B26EB8 /* LVApiHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LVApiHandler.h; sourceTree = ""; };
78 | 094273F2260096BD00B26EB8 /* LVApiHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LVApiHandler.m; sourceTree = ""; };
79 | 094273F72600993200B26EB8 /* LVTongCengWebMgr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LVTongCengWebMgr.h; sourceTree = ""; };
80 | 094273F82600993200B26EB8 /* LVTongCengWebMgr.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LVTongCengWebMgr.m; sourceTree = ""; };
81 | 0942740026009B9600B26EB8 /* LVApiHandleDelegate-Protocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "LVApiHandleDelegate-Protocol.h"; sourceTree = ""; };
82 | 0942740426009FCD00B26EB8 /* LVTongCengWebDelegate-Protocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "LVTongCengWebDelegate-Protocol.h"; sourceTree = ""; };
83 | /* End PBXFileReference section */
84 |
85 | /* Begin PBXFrameworksBuildPhase section */
86 | 090C2CF125FA0F4100330C86 /* Frameworks */ = {
87 | isa = PBXFrameworksBuildPhase;
88 | buildActionMask = 2147483647;
89 | files = (
90 | );
91 | runOnlyForDeploymentPostprocessing = 0;
92 | };
93 | 090C2D0C25FA0F4400330C86 /* Frameworks */ = {
94 | isa = PBXFrameworksBuildPhase;
95 | buildActionMask = 2147483647;
96 | files = (
97 | );
98 | runOnlyForDeploymentPostprocessing = 0;
99 | };
100 | 090C2D1725FA0F4400330C86 /* Frameworks */ = {
101 | isa = PBXFrameworksBuildPhase;
102 | buildActionMask = 2147483647;
103 | files = (
104 | );
105 | runOnlyForDeploymentPostprocessing = 0;
106 | };
107 | /* End PBXFrameworksBuildPhase section */
108 |
109 | /* Begin PBXGroup section */
110 | 090C2CEB25FA0F4100330C86 = {
111 | isa = PBXGroup;
112 | children = (
113 | 090C2CF625FA0F4100330C86 /* WeAppTongCeng */,
114 | 090C2D1225FA0F4400330C86 /* WeAppTongCengTests */,
115 | 090C2D1D25FA0F4400330C86 /* WeAppTongCengUITests */,
116 | 090C2CF525FA0F4100330C86 /* Products */,
117 | );
118 | sourceTree = "";
119 | };
120 | 090C2CF525FA0F4100330C86 /* Products */ = {
121 | isa = PBXGroup;
122 | children = (
123 | 090C2CF425FA0F4100330C86 /* WeAppTongCeng.app */,
124 | 090C2D0F25FA0F4400330C86 /* WeAppTongCengTests.xctest */,
125 | 090C2D1A25FA0F4400330C86 /* WeAppTongCengUITests.xctest */,
126 | );
127 | name = Products;
128 | sourceTree = "";
129 | };
130 | 090C2CF625FA0F4100330C86 /* WeAppTongCeng */ = {
131 | isa = PBXGroup;
132 | children = (
133 | 0942741B2600A4BF00B26EB8 /* AppDelegate */,
134 | 0936DDAC26006C5C007A65EB /* LVTongCeng */,
135 | 090C2D4D25FB1C6400330C86 /* test */,
136 | );
137 | path = WeAppTongCeng;
138 | sourceTree = "";
139 | };
140 | 090C2D1225FA0F4400330C86 /* WeAppTongCengTests */ = {
141 | isa = PBXGroup;
142 | children = (
143 | 090C2D1325FA0F4400330C86 /* WeAppTongCengTests.m */,
144 | 090C2D1525FA0F4400330C86 /* Info.plist */,
145 | );
146 | path = WeAppTongCengTests;
147 | sourceTree = "";
148 | };
149 | 090C2D1D25FA0F4400330C86 /* WeAppTongCengUITests */ = {
150 | isa = PBXGroup;
151 | children = (
152 | 090C2D1E25FA0F4400330C86 /* WeAppTongCengUITests.m */,
153 | 090C2D2025FA0F4400330C86 /* Info.plist */,
154 | );
155 | path = WeAppTongCengUITests;
156 | sourceTree = "";
157 | };
158 | 090C2D4D25FB1C6400330C86 /* test */ = {
159 | isa = PBXGroup;
160 | children = (
161 | 090C2D5425FB1CD800330C86 /* LVTongCengWebController.h */,
162 | 090C2D5525FB1CD800330C86 /* LVTongCengWebController.m */,
163 | 094273D72600919100B26EB8 /* LVWKWebController.h */,
164 | 094273D82600919100B26EB8 /* LVWKWebController.m */,
165 | 090C2D8525FB793000330C86 /* tongceng.html */,
166 | );
167 | path = test;
168 | sourceTree = "";
169 | };
170 | 0936DDAC26006C5C007A65EB /* LVTongCeng */ = {
171 | isa = PBXGroup;
172 | children = (
173 | 090C2D3125FA108100330C86 /* LVTongCengWebView.h */,
174 | 090C2D3225FA108100330C86 /* LVTongCengWebView.m */,
175 | 090C2D6E25FB1E0400330C86 /* LVContainerView.h */,
176 | 090C2D6F25FB1E0400330C86 /* LVContainerView.m */,
177 | 094273E22600967600B26EB8 /* LVWebViewBridge.h */,
178 | 094273E32600967600B26EB8 /* LVWebViewBridge.m */,
179 | 0942740026009B9600B26EB8 /* LVApiHandleDelegate-Protocol.h */,
180 | 094273F1260096BD00B26EB8 /* LVApiHandler.h */,
181 | 094273F2260096BD00B26EB8 /* LVApiHandler.m */,
182 | 094273F72600993200B26EB8 /* LVTongCengWebMgr.h */,
183 | 094273F82600993200B26EB8 /* LVTongCengWebMgr.m */,
184 | 0942740426009FCD00B26EB8 /* LVTongCengWebDelegate-Protocol.h */,
185 | 0936DCC325FF32AD007A65EB /* LVWeakProxy.h */,
186 | 0936DCC425FF32AD007A65EB /* LVWeakProxy.m */,
187 | 090C2D3825FA141700330C86 /* YYWAWebView.cpp */,
188 | );
189 | path = LVTongCeng;
190 | sourceTree = "";
191 | };
192 | 0942741B2600A4BF00B26EB8 /* AppDelegate */ = {
193 | isa = PBXGroup;
194 | children = (
195 | 090C2CF725FA0F4100330C86 /* AppDelegate.h */,
196 | 090C2CF825FA0F4100330C86 /* AppDelegate.m */,
197 | 090C2CFD25FA0F4100330C86 /* ViewController.h */,
198 | 090C2CFE25FA0F4100330C86 /* ViewController.m */,
199 | 090C2D0025FA0F4100330C86 /* Main.storyboard */,
200 | 090C2D0325FA0F4400330C86 /* Assets.xcassets */,
201 | 090C2D0525FA0F4400330C86 /* LaunchScreen.storyboard */,
202 | 090C2D0825FA0F4400330C86 /* Info.plist */,
203 | 090C2D0925FA0F4400330C86 /* main.m */,
204 | );
205 | name = AppDelegate;
206 | sourceTree = "";
207 | };
208 | /* End PBXGroup section */
209 |
210 | /* Begin PBXNativeTarget section */
211 | 090C2CF325FA0F4100330C86 /* WeAppTongCeng */ = {
212 | isa = PBXNativeTarget;
213 | buildConfigurationList = 090C2D2325FA0F4400330C86 /* Build configuration list for PBXNativeTarget "WeAppTongCeng" */;
214 | buildPhases = (
215 | 090C2CF025FA0F4100330C86 /* Sources */,
216 | 090C2CF125FA0F4100330C86 /* Frameworks */,
217 | 090C2CF225FA0F4100330C86 /* Resources */,
218 | );
219 | buildRules = (
220 | );
221 | dependencies = (
222 | );
223 | name = WeAppTongCeng;
224 | productName = WeAppTongCeng;
225 | productReference = 090C2CF425FA0F4100330C86 /* WeAppTongCeng.app */;
226 | productType = "com.apple.product-type.application";
227 | };
228 | 090C2D0E25FA0F4400330C86 /* WeAppTongCengTests */ = {
229 | isa = PBXNativeTarget;
230 | buildConfigurationList = 090C2D2625FA0F4400330C86 /* Build configuration list for PBXNativeTarget "WeAppTongCengTests" */;
231 | buildPhases = (
232 | 090C2D0B25FA0F4400330C86 /* Sources */,
233 | 090C2D0C25FA0F4400330C86 /* Frameworks */,
234 | 090C2D0D25FA0F4400330C86 /* Resources */,
235 | );
236 | buildRules = (
237 | );
238 | dependencies = (
239 | 090C2D1125FA0F4400330C86 /* PBXTargetDependency */,
240 | );
241 | name = WeAppTongCengTests;
242 | productName = WeAppTongCengTests;
243 | productReference = 090C2D0F25FA0F4400330C86 /* WeAppTongCengTests.xctest */;
244 | productType = "com.apple.product-type.bundle.unit-test";
245 | };
246 | 090C2D1925FA0F4400330C86 /* WeAppTongCengUITests */ = {
247 | isa = PBXNativeTarget;
248 | buildConfigurationList = 090C2D2925FA0F4400330C86 /* Build configuration list for PBXNativeTarget "WeAppTongCengUITests" */;
249 | buildPhases = (
250 | 090C2D1625FA0F4400330C86 /* Sources */,
251 | 090C2D1725FA0F4400330C86 /* Frameworks */,
252 | 090C2D1825FA0F4400330C86 /* Resources */,
253 | );
254 | buildRules = (
255 | );
256 | dependencies = (
257 | 090C2D1C25FA0F4400330C86 /* PBXTargetDependency */,
258 | );
259 | name = WeAppTongCengUITests;
260 | productName = WeAppTongCengUITests;
261 | productReference = 090C2D1A25FA0F4400330C86 /* WeAppTongCengUITests.xctest */;
262 | productType = "com.apple.product-type.bundle.ui-testing";
263 | };
264 | /* End PBXNativeTarget section */
265 |
266 | /* Begin PBXProject section */
267 | 090C2CEC25FA0F4100330C86 /* Project object */ = {
268 | isa = PBXProject;
269 | attributes = {
270 | LastUpgradeCheck = 1240;
271 | TargetAttributes = {
272 | 090C2CF325FA0F4100330C86 = {
273 | CreatedOnToolsVersion = 12.4;
274 | };
275 | 090C2D0E25FA0F4400330C86 = {
276 | CreatedOnToolsVersion = 12.4;
277 | TestTargetID = 090C2CF325FA0F4100330C86;
278 | };
279 | 090C2D1925FA0F4400330C86 = {
280 | CreatedOnToolsVersion = 12.4;
281 | TestTargetID = 090C2CF325FA0F4100330C86;
282 | };
283 | };
284 | };
285 | buildConfigurationList = 090C2CEF25FA0F4100330C86 /* Build configuration list for PBXProject "WeAppTongCeng" */;
286 | compatibilityVersion = "Xcode 9.3";
287 | developmentRegion = en;
288 | hasScannedForEncodings = 0;
289 | knownRegions = (
290 | en,
291 | Base,
292 | );
293 | mainGroup = 090C2CEB25FA0F4100330C86;
294 | productRefGroup = 090C2CF525FA0F4100330C86 /* Products */;
295 | projectDirPath = "";
296 | projectRoot = "";
297 | targets = (
298 | 090C2CF325FA0F4100330C86 /* WeAppTongCeng */,
299 | 090C2D0E25FA0F4400330C86 /* WeAppTongCengTests */,
300 | 090C2D1925FA0F4400330C86 /* WeAppTongCengUITests */,
301 | );
302 | };
303 | /* End PBXProject section */
304 |
305 | /* Begin PBXResourcesBuildPhase section */
306 | 090C2CF225FA0F4100330C86 /* Resources */ = {
307 | isa = PBXResourcesBuildPhase;
308 | buildActionMask = 2147483647;
309 | files = (
310 | 090C2D8625FB793000330C86 /* tongceng.html in Resources */,
311 | 090C2D0725FA0F4400330C86 /* LaunchScreen.storyboard in Resources */,
312 | 090C2D0425FA0F4400330C86 /* Assets.xcassets in Resources */,
313 | 090C2D0225FA0F4100330C86 /* Main.storyboard in Resources */,
314 | );
315 | runOnlyForDeploymentPostprocessing = 0;
316 | };
317 | 090C2D0D25FA0F4400330C86 /* Resources */ = {
318 | isa = PBXResourcesBuildPhase;
319 | buildActionMask = 2147483647;
320 | files = (
321 | );
322 | runOnlyForDeploymentPostprocessing = 0;
323 | };
324 | 090C2D1825FA0F4400330C86 /* Resources */ = {
325 | isa = PBXResourcesBuildPhase;
326 | buildActionMask = 2147483647;
327 | files = (
328 | );
329 | runOnlyForDeploymentPostprocessing = 0;
330 | };
331 | /* End PBXResourcesBuildPhase section */
332 |
333 | /* Begin PBXSourcesBuildPhase section */
334 | 090C2CF025FA0F4100330C86 /* Sources */ = {
335 | isa = PBXSourcesBuildPhase;
336 | buildActionMask = 2147483647;
337 | files = (
338 | 090C2CFF25FA0F4100330C86 /* ViewController.m in Sources */,
339 | 090C2CF925FA0F4100330C86 /* AppDelegate.m in Sources */,
340 | 094273F3260096BD00B26EB8 /* LVApiHandler.m in Sources */,
341 | 090C2D3325FA108100330C86 /* LVTongCengWebView.m in Sources */,
342 | 0936DCC525FF32AD007A65EB /* LVWeakProxy.m in Sources */,
343 | 094273D92600919100B26EB8 /* LVWKWebController.m in Sources */,
344 | 090C2D7025FB1E0400330C86 /* LVContainerView.m in Sources */,
345 | 090C2D0A25FA0F4400330C86 /* main.m in Sources */,
346 | 094273F92600993200B26EB8 /* LVTongCengWebMgr.m in Sources */,
347 | 090C2D5625FB1CD800330C86 /* LVTongCengWebController.m in Sources */,
348 | 094273E42600967600B26EB8 /* LVWebViewBridge.m in Sources */,
349 | );
350 | runOnlyForDeploymentPostprocessing = 0;
351 | };
352 | 090C2D0B25FA0F4400330C86 /* Sources */ = {
353 | isa = PBXSourcesBuildPhase;
354 | buildActionMask = 2147483647;
355 | files = (
356 | 090C2D1425FA0F4400330C86 /* WeAppTongCengTests.m in Sources */,
357 | );
358 | runOnlyForDeploymentPostprocessing = 0;
359 | };
360 | 090C2D1625FA0F4400330C86 /* Sources */ = {
361 | isa = PBXSourcesBuildPhase;
362 | buildActionMask = 2147483647;
363 | files = (
364 | 090C2D1F25FA0F4400330C86 /* WeAppTongCengUITests.m in Sources */,
365 | );
366 | runOnlyForDeploymentPostprocessing = 0;
367 | };
368 | /* End PBXSourcesBuildPhase section */
369 |
370 | /* Begin PBXTargetDependency section */
371 | 090C2D1125FA0F4400330C86 /* PBXTargetDependency */ = {
372 | isa = PBXTargetDependency;
373 | target = 090C2CF325FA0F4100330C86 /* WeAppTongCeng */;
374 | targetProxy = 090C2D1025FA0F4400330C86 /* PBXContainerItemProxy */;
375 | };
376 | 090C2D1C25FA0F4400330C86 /* PBXTargetDependency */ = {
377 | isa = PBXTargetDependency;
378 | target = 090C2CF325FA0F4100330C86 /* WeAppTongCeng */;
379 | targetProxy = 090C2D1B25FA0F4400330C86 /* PBXContainerItemProxy */;
380 | };
381 | /* End PBXTargetDependency section */
382 |
383 | /* Begin PBXVariantGroup section */
384 | 090C2D0025FA0F4100330C86 /* Main.storyboard */ = {
385 | isa = PBXVariantGroup;
386 | children = (
387 | 090C2D0125FA0F4100330C86 /* Base */,
388 | );
389 | name = Main.storyboard;
390 | sourceTree = "";
391 | };
392 | 090C2D0525FA0F4400330C86 /* LaunchScreen.storyboard */ = {
393 | isa = PBXVariantGroup;
394 | children = (
395 | 090C2D0625FA0F4400330C86 /* Base */,
396 | );
397 | name = LaunchScreen.storyboard;
398 | sourceTree = "";
399 | };
400 | /* End PBXVariantGroup section */
401 |
402 | /* Begin XCBuildConfiguration section */
403 | 090C2D2125FA0F4400330C86 /* Debug */ = {
404 | isa = XCBuildConfiguration;
405 | buildSettings = {
406 | ALWAYS_SEARCH_USER_PATHS = NO;
407 | CLANG_ANALYZER_NONNULL = YES;
408 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
409 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
410 | CLANG_CXX_LIBRARY = "libc++";
411 | CLANG_ENABLE_MODULES = YES;
412 | CLANG_ENABLE_OBJC_ARC = YES;
413 | CLANG_ENABLE_OBJC_WEAK = YES;
414 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
415 | CLANG_WARN_BOOL_CONVERSION = YES;
416 | CLANG_WARN_COMMA = YES;
417 | CLANG_WARN_CONSTANT_CONVERSION = YES;
418 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
419 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
420 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
421 | CLANG_WARN_EMPTY_BODY = YES;
422 | CLANG_WARN_ENUM_CONVERSION = YES;
423 | CLANG_WARN_INFINITE_RECURSION = YES;
424 | CLANG_WARN_INT_CONVERSION = YES;
425 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
426 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
427 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
428 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
429 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
430 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
431 | CLANG_WARN_STRICT_PROTOTYPES = YES;
432 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
433 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
434 | CLANG_WARN_UNREACHABLE_CODE = YES;
435 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
436 | COPY_PHASE_STRIP = NO;
437 | DEBUG_INFORMATION_FORMAT = dwarf;
438 | ENABLE_STRICT_OBJC_MSGSEND = YES;
439 | ENABLE_TESTABILITY = YES;
440 | GCC_C_LANGUAGE_STANDARD = gnu11;
441 | GCC_DYNAMIC_NO_PIC = NO;
442 | GCC_NO_COMMON_BLOCKS = YES;
443 | GCC_OPTIMIZATION_LEVEL = 0;
444 | GCC_PREPROCESSOR_DEFINITIONS = (
445 | "DEBUG=1",
446 | "$(inherited)",
447 | );
448 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
449 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
450 | GCC_WARN_UNDECLARED_SELECTOR = YES;
451 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
452 | GCC_WARN_UNUSED_FUNCTION = YES;
453 | GCC_WARN_UNUSED_VARIABLE = YES;
454 | IPHONEOS_DEPLOYMENT_TARGET = 14.4;
455 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
456 | MTL_FAST_MATH = YES;
457 | ONLY_ACTIVE_ARCH = YES;
458 | SDKROOT = iphoneos;
459 | };
460 | name = Debug;
461 | };
462 | 090C2D2225FA0F4400330C86 /* Release */ = {
463 | isa = XCBuildConfiguration;
464 | buildSettings = {
465 | ALWAYS_SEARCH_USER_PATHS = NO;
466 | CLANG_ANALYZER_NONNULL = YES;
467 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
468 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
469 | CLANG_CXX_LIBRARY = "libc++";
470 | CLANG_ENABLE_MODULES = YES;
471 | CLANG_ENABLE_OBJC_ARC = YES;
472 | CLANG_ENABLE_OBJC_WEAK = YES;
473 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
474 | CLANG_WARN_BOOL_CONVERSION = YES;
475 | CLANG_WARN_COMMA = YES;
476 | CLANG_WARN_CONSTANT_CONVERSION = YES;
477 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
478 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
479 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
480 | CLANG_WARN_EMPTY_BODY = YES;
481 | CLANG_WARN_ENUM_CONVERSION = YES;
482 | CLANG_WARN_INFINITE_RECURSION = YES;
483 | CLANG_WARN_INT_CONVERSION = YES;
484 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
485 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
486 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
487 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
488 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
489 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
490 | CLANG_WARN_STRICT_PROTOTYPES = YES;
491 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
492 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
493 | CLANG_WARN_UNREACHABLE_CODE = YES;
494 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
495 | COPY_PHASE_STRIP = NO;
496 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
497 | ENABLE_NS_ASSERTIONS = NO;
498 | ENABLE_STRICT_OBJC_MSGSEND = YES;
499 | GCC_C_LANGUAGE_STANDARD = gnu11;
500 | GCC_NO_COMMON_BLOCKS = YES;
501 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
502 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
503 | GCC_WARN_UNDECLARED_SELECTOR = YES;
504 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
505 | GCC_WARN_UNUSED_FUNCTION = YES;
506 | GCC_WARN_UNUSED_VARIABLE = YES;
507 | IPHONEOS_DEPLOYMENT_TARGET = 14.4;
508 | MTL_ENABLE_DEBUG_INFO = NO;
509 | MTL_FAST_MATH = YES;
510 | SDKROOT = iphoneos;
511 | VALIDATE_PRODUCT = YES;
512 | };
513 | name = Release;
514 | };
515 | 090C2D2425FA0F4400330C86 /* Debug */ = {
516 | isa = XCBuildConfiguration;
517 | buildSettings = {
518 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
519 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
520 | CODE_SIGN_STYLE = Automatic;
521 | DEVELOPMENT_TEAM = 9PJ22KK765;
522 | INFOPLIST_FILE = WeAppTongCeng/Info.plist;
523 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
524 | LD_RUNPATH_SEARCH_PATHS = (
525 | "$(inherited)",
526 | "@executable_path/Frameworks",
527 | );
528 | PRODUCT_BUNDLE_IDENTIFIER = com.lionvoom.WeAppTongCeng.1;
529 | PRODUCT_NAME = "$(TARGET_NAME)";
530 | TARGETED_DEVICE_FAMILY = "1,2";
531 | };
532 | name = Debug;
533 | };
534 | 090C2D2525FA0F4400330C86 /* Release */ = {
535 | isa = XCBuildConfiguration;
536 | buildSettings = {
537 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
538 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
539 | CODE_SIGN_STYLE = Automatic;
540 | DEVELOPMENT_TEAM = 9PJ22KK765;
541 | INFOPLIST_FILE = WeAppTongCeng/Info.plist;
542 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
543 | LD_RUNPATH_SEARCH_PATHS = (
544 | "$(inherited)",
545 | "@executable_path/Frameworks",
546 | );
547 | PRODUCT_BUNDLE_IDENTIFIER = com.lionvoom.WeAppTongCeng.1;
548 | PRODUCT_NAME = "$(TARGET_NAME)";
549 | TARGETED_DEVICE_FAMILY = "1,2";
550 | };
551 | name = Release;
552 | };
553 | 090C2D2725FA0F4400330C86 /* Debug */ = {
554 | isa = XCBuildConfiguration;
555 | buildSettings = {
556 | BUNDLE_LOADER = "$(TEST_HOST)";
557 | CODE_SIGN_STYLE = Automatic;
558 | DEVELOPMENT_TEAM = 9PJ22KK765;
559 | INFOPLIST_FILE = WeAppTongCengTests/Info.plist;
560 | IPHONEOS_DEPLOYMENT_TARGET = 14.4;
561 | LD_RUNPATH_SEARCH_PATHS = (
562 | "$(inherited)",
563 | "@executable_path/Frameworks",
564 | "@loader_path/Frameworks",
565 | );
566 | PRODUCT_BUNDLE_IDENTIFIER = com.lionvoom.WeAppTongCengTests;
567 | PRODUCT_NAME = "$(TARGET_NAME)";
568 | TARGETED_DEVICE_FAMILY = "1,2";
569 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WeAppTongCeng.app/WeAppTongCeng";
570 | };
571 | name = Debug;
572 | };
573 | 090C2D2825FA0F4400330C86 /* Release */ = {
574 | isa = XCBuildConfiguration;
575 | buildSettings = {
576 | BUNDLE_LOADER = "$(TEST_HOST)";
577 | CODE_SIGN_STYLE = Automatic;
578 | DEVELOPMENT_TEAM = 9PJ22KK765;
579 | INFOPLIST_FILE = WeAppTongCengTests/Info.plist;
580 | IPHONEOS_DEPLOYMENT_TARGET = 14.4;
581 | LD_RUNPATH_SEARCH_PATHS = (
582 | "$(inherited)",
583 | "@executable_path/Frameworks",
584 | "@loader_path/Frameworks",
585 | );
586 | PRODUCT_BUNDLE_IDENTIFIER = com.lionvoom.WeAppTongCengTests;
587 | PRODUCT_NAME = "$(TARGET_NAME)";
588 | TARGETED_DEVICE_FAMILY = "1,2";
589 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WeAppTongCeng.app/WeAppTongCeng";
590 | };
591 | name = Release;
592 | };
593 | 090C2D2A25FA0F4400330C86 /* Debug */ = {
594 | isa = XCBuildConfiguration;
595 | buildSettings = {
596 | CODE_SIGN_STYLE = Automatic;
597 | DEVELOPMENT_TEAM = 9PJ22KK765;
598 | INFOPLIST_FILE = WeAppTongCengUITests/Info.plist;
599 | LD_RUNPATH_SEARCH_PATHS = (
600 | "$(inherited)",
601 | "@executable_path/Frameworks",
602 | "@loader_path/Frameworks",
603 | );
604 | PRODUCT_BUNDLE_IDENTIFIER = com.lionvoom.WeAppTongCengUITests;
605 | PRODUCT_NAME = "$(TARGET_NAME)";
606 | TARGETED_DEVICE_FAMILY = "1,2";
607 | TEST_TARGET_NAME = WeAppTongCeng;
608 | };
609 | name = Debug;
610 | };
611 | 090C2D2B25FA0F4400330C86 /* Release */ = {
612 | isa = XCBuildConfiguration;
613 | buildSettings = {
614 | CODE_SIGN_STYLE = Automatic;
615 | DEVELOPMENT_TEAM = 9PJ22KK765;
616 | INFOPLIST_FILE = WeAppTongCengUITests/Info.plist;
617 | LD_RUNPATH_SEARCH_PATHS = (
618 | "$(inherited)",
619 | "@executable_path/Frameworks",
620 | "@loader_path/Frameworks",
621 | );
622 | PRODUCT_BUNDLE_IDENTIFIER = com.lionvoom.WeAppTongCengUITests;
623 | PRODUCT_NAME = "$(TARGET_NAME)";
624 | TARGETED_DEVICE_FAMILY = "1,2";
625 | TEST_TARGET_NAME = WeAppTongCeng;
626 | };
627 | name = Release;
628 | };
629 | /* End XCBuildConfiguration section */
630 |
631 | /* Begin XCConfigurationList section */
632 | 090C2CEF25FA0F4100330C86 /* Build configuration list for PBXProject "WeAppTongCeng" */ = {
633 | isa = XCConfigurationList;
634 | buildConfigurations = (
635 | 090C2D2125FA0F4400330C86 /* Debug */,
636 | 090C2D2225FA0F4400330C86 /* Release */,
637 | );
638 | defaultConfigurationIsVisible = 0;
639 | defaultConfigurationName = Release;
640 | };
641 | 090C2D2325FA0F4400330C86 /* Build configuration list for PBXNativeTarget "WeAppTongCeng" */ = {
642 | isa = XCConfigurationList;
643 | buildConfigurations = (
644 | 090C2D2425FA0F4400330C86 /* Debug */,
645 | 090C2D2525FA0F4400330C86 /* Release */,
646 | );
647 | defaultConfigurationIsVisible = 0;
648 | defaultConfigurationName = Release;
649 | };
650 | 090C2D2625FA0F4400330C86 /* Build configuration list for PBXNativeTarget "WeAppTongCengTests" */ = {
651 | isa = XCConfigurationList;
652 | buildConfigurations = (
653 | 090C2D2725FA0F4400330C86 /* Debug */,
654 | 090C2D2825FA0F4400330C86 /* Release */,
655 | );
656 | defaultConfigurationIsVisible = 0;
657 | defaultConfigurationName = Release;
658 | };
659 | 090C2D2925FA0F4400330C86 /* Build configuration list for PBXNativeTarget "WeAppTongCengUITests" */ = {
660 | isa = XCConfigurationList;
661 | buildConfigurations = (
662 | 090C2D2A25FA0F4400330C86 /* Debug */,
663 | 090C2D2B25FA0F4400330C86 /* Release */,
664 | );
665 | defaultConfigurationIsVisible = 0;
666 | defaultConfigurationName = Release;
667 | };
668 | /* End XCConfigurationList section */
669 | };
670 | rootObject = 090C2CEC25FA0F4100330C86 /* Project object */;
671 | }
672 |
--------------------------------------------------------------------------------
/WeAppTongCeng/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/11.
6 | //
7 |
8 | #import
9 |
10 | @interface AppDelegate : UIResponder
11 | @property (nonatomic, strong) UIWindow *window;
12 | @end
13 |
14 |
--------------------------------------------------------------------------------
/WeAppTongCeng/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/11.
6 | //
7 |
8 | #import "AppDelegate.h"
9 | @interface AppDelegate ()
10 |
11 | @end
12 |
13 | @implementation AppDelegate
14 |
15 |
16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
17 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
18 | self.window.backgroundColor = [UIColor whiteColor];
19 | UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
20 | UIViewController *vc = sb.instantiateInitialViewController;
21 | self.window.rootViewController = vc;
22 | [self.window makeKeyAndVisible];
23 | return YES;
24 | }
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/WeAppTongCeng/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/WeAppTongCeng/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/WeAppTongCeng/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/WeAppTongCeng/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 |
--------------------------------------------------------------------------------
/WeAppTongCeng/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
29 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/WeAppTongCeng/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSupportsIndirectInputEvents
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 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationPortraitUpsideDown
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/WeAppTongCeng/LVTongCeng/LVApiHandleDelegate-Protocol.h:
--------------------------------------------------------------------------------
1 | //
2 | // LVApiHandleDelegate-Protocol.h
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/16.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @protocol LVApiHandleDelegate
13 |
14 | - (void)webView:(WKWebView *)webView invoke:(NSDictionary *)jsonData;
15 |
16 | @end
17 |
18 | NS_ASSUME_NONNULL_END
19 |
--------------------------------------------------------------------------------
/WeAppTongCeng/LVTongCeng/LVApiHandler.h:
--------------------------------------------------------------------------------
1 | //
2 | // LVApiHandler.h
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/16.
6 | //
7 |
8 | #import
9 | #import "LVApiHandleDelegate-Protocol.h"
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface LVApiHandler : NSObject
14 |
15 | @end
16 |
17 | NS_ASSUME_NONNULL_END
18 |
--------------------------------------------------------------------------------
/WeAppTongCeng/LVTongCeng/LVApiHandler.m:
--------------------------------------------------------------------------------
1 | //
2 | // LVApiHandler.m
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/16.
6 | //
7 |
8 | #import "LVApiHandler.h"
9 | #import
10 | #import "LVContainerView.h"
11 |
12 | @implementation LVApiHandler
13 |
14 | #pragma mark - LVApiHandleDelegate
15 | - (void)webView:(WKWebView *)webView invoke:(NSDictionary *)jsonData {
16 | NSString *api = jsonData[@"api"];
17 | NSDictionary *args = jsonData[@"args"];
18 | UIView *containerSuperview = [self dfsSearch:webView.scrollView containerId:args[@"cid"]];
19 | if (!containerSuperview) return;
20 | LVContainerView *containerView = [self insertContainerView:containerSuperview];
21 | if ([api isEqualToString:@"insertInput"]) {
22 | [self insertInput:containerView];
23 | } else if ([api isEqualToString:@"insertTextArea"]) {
24 | [self insertTextArea:containerView];
25 | } else if ([api isEqualToString:@"insertVideo"]) {
26 | [self insertVideo:containerView];
27 | }
28 | }
29 |
30 | - (UIView *)dfsSearch:(UIView *)view containerId:(NSNumber *)containerId {
31 | //TODO: optimize
32 | NSString *str = [NSString stringWithFormat:@"class='container cid_%@'", containerId];
33 | Class clz = NSClassFromString(@"WKCompositingView");
34 | if ([view isKindOfClass:clz] && [[[view layer] name] hasSuffix:str]) {
35 | UIView *_WKChildScrollView = view.subviews.firstObject;
36 | if (![_WKChildScrollView isKindOfClass:NSClassFromString(@"WKChildScrollView")]) return nil;
37 | for (UIGestureRecognizer *ges in _WKChildScrollView.gestureRecognizers) {
38 | [_WKChildScrollView removeGestureRecognizer:ges];
39 | }
40 | return _WKChildScrollView;
41 | }
42 | for (UIView *subView in view.subviews) {
43 | UIView *findView = [self dfsSearch:subView containerId:containerId];
44 | if (findView) return findView;
45 | }
46 | return nil;
47 | }
48 |
49 | - (void)insertInput:(LVContainerView *)containerView {
50 | UITextField *textField = [[UITextField alloc] initWithFrame:containerView.bounds];
51 | textField.backgroundColor = UIColor.lightGrayColor;
52 | textField.font = [UIFont systemFontOfSize:20];
53 | textField.text = @"微信小程序同层渲染";
54 | [containerView addSubview:textField];
55 | }
56 |
57 | - (void)insertTextArea:(LVContainerView *)containerView {
58 | UITextView *textView = [[UITextView alloc] initWithFrame:containerView.bounds];
59 | textView.backgroundColor = UIColor.brownColor;
60 | textView.font = [UIFont systemFontOfSize:30];
61 | textView.text = @"微信小程序同层渲染效果实现";
62 | [containerView addSubview:textView];
63 | }
64 |
65 | - (void)insertVideo:(LVContainerView *)containerView {
66 | UIButton *btn = [[UIButton alloc] initWithFrame:containerView.bounds];
67 | btn.backgroundColor = UIColor.blueColor;
68 | [btn setTitle:@"请替换成video组件" forState:UIControlStateNormal];
69 | [containerView addSubview:btn];
70 | [btn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];
71 | }
72 |
73 | - (LVContainerView *)insertContainerView:(UIView *)containerSuperview {
74 | LVContainerView *containerView = [[LVContainerView alloc] initWithFrame:containerSuperview.bounds];
75 | [containerSuperview addSubview:containerView];
76 | return containerView;
77 | }
78 |
79 | - (void)btnAction:(UIView *)view {
80 | UIColor * randomColor= [UIColor colorWithRed:((float)arc4random_uniform(256) / 255.0) green:((float)arc4random_uniform(256) / 255.0) blue:((float)arc4random_uniform(256) / 255.0) alpha:1.0];
81 | view.backgroundColor = randomColor;
82 | }
83 |
84 | @end
85 |
--------------------------------------------------------------------------------
/WeAppTongCeng/LVTongCeng/LVContainerView.h:
--------------------------------------------------------------------------------
1 | //
2 | // LVContainerView.h
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/12.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface LVContainerView : UIView
13 | @end
14 |
15 | NS_ASSUME_NONNULL_END
16 |
--------------------------------------------------------------------------------
/WeAppTongCeng/LVTongCeng/LVContainerView.m:
--------------------------------------------------------------------------------
1 | //
2 | // LVContainerView.m
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/12.
6 | //
7 |
8 | #import "LVContainerView.h"
9 |
10 | @implementation LVContainerView
11 |
12 | // LVContainerView conforms protocol WKNativelyInteractible
13 | - (BOOL)conformsToProtocol:(Protocol *)aProtocol {
14 | if (aProtocol == NSProtocolFromString(@"WKNativelyInteractible")) {
15 | return YES;
16 | }
17 | return [super conformsToProtocol:aProtocol];
18 | }
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/WeAppTongCeng/LVTongCeng/LVTongCengWebDelegate-Protocol.h:
--------------------------------------------------------------------------------
1 | //
2 | // LVTongCengWebDelegate-Protocol.h
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/16.
6 | //
7 |
8 | #import
9 | #import "LVApiHandleDelegate-Protocol.h"
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @protocol LVTongCengWebDelegate
14 | @property (readonly) id apiHandler;
15 | @end
16 |
17 | NS_ASSUME_NONNULL_END
18 |
--------------------------------------------------------------------------------
/WeAppTongCeng/LVTongCeng/LVTongCengWebMgr.h:
--------------------------------------------------------------------------------
1 | //
2 | // LVTongCengWebMgr.h
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/16.
6 | //
7 |
8 | #import
9 | #import "LVTongCengWebDelegate-Protocol.h"
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface LVTongCengWebMgr : NSObject
14 |
15 | @end
16 |
17 | NS_ASSUME_NONNULL_END
18 |
--------------------------------------------------------------------------------
/WeAppTongCeng/LVTongCeng/LVTongCengWebMgr.m:
--------------------------------------------------------------------------------
1 | //
2 | // LVTongCengWebMgr.m
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/16.
6 | //
7 |
8 | #import "LVTongCengWebMgr.h"
9 | #import "LVApiHandler.h"
10 |
11 | @interface LVTongCengWebMgr()
12 | @property (nonatomic, strong) LVApiHandler *apiHandler;
13 | @end
14 |
15 | @implementation LVTongCengWebMgr
16 |
17 | - (instancetype)init {
18 | self = [super init];
19 | if (self) {
20 | self.apiHandler = [[LVApiHandler alloc] init];
21 | }
22 | return self;
23 | }
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/WeAppTongCeng/LVTongCeng/LVTongCengWebView.h:
--------------------------------------------------------------------------------
1 | //
2 | // LVTongCengWebView.h
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/11.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface LVTongCengWebView : WKWebView
13 |
14 | @end
15 |
16 | NS_ASSUME_NONNULL_END
17 |
--------------------------------------------------------------------------------
/WeAppTongCeng/LVTongCeng/LVTongCengWebView.m:
--------------------------------------------------------------------------------
1 | //
2 | // LVTongCengWebView.m
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/11.
6 | //
7 |
8 | #import "LVTongCengWebView.h"
9 |
10 | @interface LVTongCengWebView()
11 | @property (nonatomic, assign) BOOL didHandleWKContentGestrues;
12 | @end
13 |
14 | @implementation LVTongCengWebView
15 |
16 | - (void)_handleWKContentGestrues {
17 | UIScrollView *webViewScrollView = self.scrollView;
18 | if ([webViewScrollView isKindOfClass:NSClassFromString(@"WKScrollView")]) {
19 | UIView *_WKContentView = webViewScrollView.subviews.firstObject;
20 | if (![_WKContentView isKindOfClass:NSClassFromString(@"WKContentView")]) return;
21 | NSArray *gestrues = _WKContentView.gestureRecognizers;
22 | Class clz = NSClassFromString(@"UITextTapRecognizer");
23 | for (UIGestureRecognizer *gesture in gestrues) {
24 | // fix: 原生输入框聚焦时, 再次点击会失焦
25 | if ([gesture isKindOfClass:clz]) {
26 | gesture.enabled = NO;
27 | continue;
28 | }
29 | gesture.cancelsTouchesInView = NO;
30 | gesture.delaysTouchesBegan = NO;
31 | gesture.delaysTouchesEnded = NO;
32 | }
33 | }
34 | }
35 |
36 | - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
37 | UIView *wkHitView = [super hitTest:point withEvent:event];
38 |
39 | // Handling the WKContentView GestureRecognizers interception event causing the inserted native control to fail to respond
40 | if (!self.didHandleWKContentGestrues) {
41 | [self _handleWKContentGestrues];
42 | self.didHandleWKContentGestrues = YES;
43 | }
44 |
45 | // Plan A: LVContainerView conforms to protocol WKNativelyInteractible
46 |
47 | // Plan B: WKChildScrollView -[hitTest:withEvent:]
48 | // if ([wkHitView isKindOfClass:NSClassFromString(@"WKChildScrollView")]) {
49 | // for (UIView *subview in [wkHitView.subviews reverseObjectEnumerator]) {
50 | // CGPoint convertedPoint = [subview convertPoint:point fromView:self];
51 | // UIView *hitTestView = [subview hitTest:convertedPoint withEvent:event];
52 | // if (hitTestView) {
53 | // wkHitView = hitTestView;
54 | // break;
55 | // }
56 | // }
57 | // }
58 |
59 | // NSLog(@"hitTest: %@", wkHitView);
60 | return wkHitView;
61 | }
62 |
63 | @end
64 |
--------------------------------------------------------------------------------
/WeAppTongCeng/LVTongCeng/LVWeakProxy.h:
--------------------------------------------------------------------------------
1 | //
2 | // LVWeakProxy.h
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/15.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface LVWeakProxy : NSProxy
13 | @property (nullable, nonatomic, weak, readonly) id target;
14 |
15 | - (instancetype)initWithTarget:(id)target;
16 |
17 | + (instancetype)proxyWithTarget:(id)target;
18 |
19 | @end
20 |
21 | NS_ASSUME_NONNULL_END
22 |
--------------------------------------------------------------------------------
/WeAppTongCeng/LVTongCeng/LVWeakProxy.m:
--------------------------------------------------------------------------------
1 | //
2 | // LVWeakProxy.m
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/15.
6 | //
7 |
8 | #import "LVWeakProxy.h"
9 |
10 | @implementation LVWeakProxy
11 |
12 | - (instancetype)initWithTarget:(id)target {
13 | _target = target;
14 | return self;
15 | }
16 |
17 | + (instancetype)proxyWithTarget:(id)target {
18 | return [[self alloc] initWithTarget:target];
19 | }
20 |
21 | - (id)forwardingTargetForSelector:(SEL)selector {
22 | return _target;
23 | }
24 |
25 | - (void)forwardInvocation:(NSInvocation *)invocation {
26 | void *null = NULL;
27 | [invocation setReturnValue:&null];
28 | }
29 |
30 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
31 | return [NSObject instanceMethodSignatureForSelector:@selector(init)];
32 | }
33 |
34 | - (BOOL)respondsToSelector:(SEL)aSelector {
35 | return [_target respondsToSelector:aSelector];
36 | }
37 |
38 | - (BOOL)isEqual:(id)object {
39 | return [_target isEqual:object];
40 | }
41 |
42 | - (NSUInteger)hash {
43 | return [_target hash];
44 | }
45 |
46 | - (Class)superclass {
47 | return [_target superclass];
48 | }
49 |
50 | - (Class)class {
51 | return [_target class];
52 | }
53 |
54 | - (BOOL)isKindOfClass:(Class)aClass {
55 | return [_target isKindOfClass:aClass];
56 | }
57 |
58 | - (BOOL)isMemberOfClass:(Class)aClass {
59 | return [_target isMemberOfClass:aClass];
60 | }
61 |
62 | - (BOOL)conformsToProtocol:(Protocol *)aProtocol {
63 | return [_target conformsToProtocol:aProtocol];
64 | }
65 |
66 | - (BOOL)isProxy {
67 | return YES;
68 | }
69 |
70 | - (NSString *)description {
71 | return [_target description];
72 | }
73 |
74 | - (NSString *)debugDescription {
75 | return [_target debugDescription];
76 | }
77 |
78 | @end
79 |
--------------------------------------------------------------------------------
/WeAppTongCeng/LVTongCeng/LVWebViewBridge.h:
--------------------------------------------------------------------------------
1 | //
2 | // LVWebViewBridge.h
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/16.
6 | //
7 |
8 | #import
9 | #import "LVTongCengWebDelegate-Protocol.h"
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface LVWebViewBridge : NSObject
14 |
15 | - (instancetype)initWithDelegate:(id)delegate;
16 |
17 | - (WKWebViewConfiguration *)genBridgeOfWKUserContentController;
18 |
19 | @end
20 |
21 | NS_ASSUME_NONNULL_END
22 |
--------------------------------------------------------------------------------
/WeAppTongCeng/LVTongCeng/LVWebViewBridge.m:
--------------------------------------------------------------------------------
1 | //
2 | // LVWebViewBridge.m
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/16.
6 | //
7 |
8 | #import "LVWebViewBridge.h"
9 | #import "LVWeakProxy.h"
10 |
11 | @interface LVWebViewBridge()
12 | @property (nonatomic, weak) id delegate;
13 | @end
14 |
15 | @implementation LVWebViewBridge
16 |
17 | - (instancetype)initWithDelegate:(id)delegate {
18 | if (self = [super init]) {
19 | self.delegate = delegate;
20 | }
21 | return self;
22 | }
23 |
24 | - (WKWebViewConfiguration *)genBridgeOfWKUserContentController {
25 | WKUserContentController *userContentController = WKUserContentController.new;
26 | LVWeakProxy *weakProxy = [LVWeakProxy proxyWithTarget:self];
27 | [userContentController addScriptMessageHandler:(id)weakProxy name:@"handle"];
28 | WKWebViewConfiguration *configuration = [WKWebViewConfiguration new];
29 | configuration.userContentController = userContentController;
30 | return configuration;
31 | }
32 |
33 | #pragma mark - WKScriptMessageHandler
34 | - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
35 | NSString *name = message.name;
36 | id body = message.body;
37 | NSString *selName = [NSString stringWithFormat:@"webView:%@:", name];
38 | SEL selector = NSSelectorFromString(selName);
39 | #pragma clang diagnostic push
40 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
41 | if (![self respondsToSelector:selector]) {
42 | NSLog(@"[NO IMP]:%@", selName);
43 | return;
44 | }
45 | [self performSelector:selector withObject:message.webView withObject:body];
46 | #pragma clang diagnostic pop
47 | }
48 |
49 | - (void)webView:(WKWebView *)webView handle:(NSDictionary *)jsonData {
50 | [self.delegate.apiHandler webView:webView invoke:jsonData];
51 | }
52 |
53 | @end
54 |
--------------------------------------------------------------------------------
/WeAppTongCeng/LVTongCeng/YYWAWebView.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | wx小程序同层渲染伪代码 -[YYWAWebView hitTest:withEvent:]
3 | */
4 |
5 | // local variable allocation has failed, the output may be wrong!
6 | id __cdecl -[YYWAWebView hitTest:withEvent:](YYWAWebView *self, SEL a2, CGPoint a3, id a4)
7 | {
8 | double v4; // d8
9 | double v5; // d9
10 | YYWAWebView *v6; // x20
11 | struct objc_object *v7; // x19
12 | __int64 v8; // x22
13 | Class v9; // x23
14 | void *v10; // x24
15 | __int64 v11; // x25
16 | __int64 v12; // x23
17 | __int64 v13; // x0
18 | __int64 v14; // x23
19 | __int64 v15; // x24
20 | YYWAWebView *v17; // [xsp+10h] [xbp-60h]
21 | __objc2_class *v18; // [xsp+18h] [xbp-58h]
22 | CGPoint v19; // 0:d0.8,8:d1.8
23 |
24 | v4 = a3.var1;
25 | v5 = a3.var0;
26 | v6 = self;
27 | v7 = (struct objc_object *)objc_retain();
28 | -[YYWAWebView setIsHitSelectableText:](v6, "setIsHitSelectableText:", 0LL);
29 | -[YYWAWebView setIsHitTongCeng:](v6, "setIsHitTongCeng:", 0LL);
30 | v17 = v6;
31 | v18 = &OBJC_CLASS___YYWAWebView;
32 | objc_msgSendSuper2(&v17, "hitTest:withEvent:", v7, v5, v4);
33 | v8 = objc_retainAutoreleasedReturnValue();
34 | -[YYWAWebView setWkHitView:](v6, "setWkHitView:", v8);
35 | objc_release(v8);
36 | v9 = ((Class (__cdecl *)(WALogService_meta *, SEL))objc_msgSend)(
37 | (WALogService_meta *)&OBJC_CLASS___WALogService,
38 | "externalIMP");
39 | ((void (__cdecl *)(YYWAWebView *, SEL))objc_msgSend)(v6, "wkHitView");
40 | v10 = (void *)objc_retainAutoreleasedReturnValue();
41 | objc_msgSend(v10, "clsptr");
42 | v11 = objc_retainAutoreleasedReturnValue();
43 | objc_msgSend(
44 | v9,
45 | "logWithLevel:module:errorCode:file:line:func:format:",
46 | 2LL,
47 | "WeApp",
48 | 0LL,
49 | "YYWAWebView.mm",
50 | 617LL,
51 | "-[YYWAWebView hitTest:withEvent:]",
52 | CFSTR("WKTongCeng wkHitView=%@"),
53 | v11);
54 | objc_release(v11);
55 | objc_release(v10);
56 | ((void (__cdecl *)(YYWAWebView *, SEL))objc_msgSend)(v6, "nativeDelegate");
57 | v12 = objc_retainAutoreleasedReturnValue();
58 | objc_release(v12);
59 | if ( !v12
60 | || (v19.var0 = v5,
61 | v19.var1 = v4,
62 | ((void (__cdecl *)(YYWAWebView *, SEL, id, CGPoint, id))objc_msgSend)(
63 | v6,
64 | "hitWKWebNativeTest:point:withEvent:",
65 | (id)v6,
66 | v19,
67 | v7),
68 | (v13 = objc_retainAutoreleasedReturnValue()) == 0) )
69 | {
70 | v15 = 0LL;
71 | LABEL_7:
72 | ((void (__cdecl *)(YYWAWebView *, SEL))objc_msgSend)(v6, "wkHitView");
73 | v14 = objc_retainAutoreleasedReturnValue();
74 | objc_release(v15);
75 | goto LABEL_8;
76 | }
77 | v14 = v13;
78 | v15 = v13;
79 | if ( !(unsigned int)-[YYWAWebView isHitTongCeng](v6, "isHitTongCeng") )
80 | goto LABEL_7;
81 | v15 = v14;
82 | if ( (unsigned int)-[YYWAWebView isHitSelectableText](v6, "isHitSelectableText") )
83 | goto LABEL_7;
84 | LABEL_8:
85 | -[YYWAWebView setWkHitView:](v6, "setWkHitView:", 0LL);
86 | objc_release(v7);
87 | return (id)objc_autoreleaseReturnValue(v14);
88 | }
89 |
90 |
91 | // local variable allocation has failed, the output may be wrong!
92 | id __cdecl -[YYWAWebView hitWKWebNativeTest:point:withEvent:](YYWAWebView *self, SEL a2, id a3, CGPoint a4, id a5)
93 | {
94 | double v5; // d8
95 | double v6; // d9
96 | YYWAWebView *v7; // x22
97 | void *v8; // x26
98 | struct objc_object *v9; // x27
99 | void *v10; // x20
100 | int v11; // w21
101 | __int64 v12; // x25
102 | const char *v13; // x1
103 | void *v14; // x19
104 | __int64 v15; // x20
105 | void *v16; // x20
106 | char *v17; // x23
107 | signed __int64 v18; // x23
108 | void *v19; // x25
109 | struct objc_object *v20; // x24
110 | __int64 v21; // x19
111 | __int64 v22; // x19
112 | __int64 v23; // x0
113 | __int64 v24; // x21
114 | void *v25; // x0
115 | void *v26; // x22
116 | int v27; // w23
117 | __int64 v28; // x1
118 | YYWAWebView *v29; // x26
119 | unsigned __int64 v30; // x24
120 | void *v31; // x20
121 | __int64 v32; // x28
122 | void *v33; // x0
123 | __int64 v34; // x22
124 | void *v35; // x26
125 | void *v36; // x19
126 | void *v37; // x0
127 | void *v38; // x26
128 | void *v39; // x0
129 | void *v40; // x0
130 | void *v41; // x26
131 | void *v42; // x0
132 | void *v43; // x0
133 | void *v44; // x20
134 | void *v45; // x26
135 | void *v46; // x0
136 | id result; // x0
137 | __int64 v48; // [xsp+0h] [xbp-1E0h]
138 | struct objc_object *v49; // [xsp+8h] [xbp-1D8h]
139 | void *v50; // [xsp+10h] [xbp-1D0h]
140 | void *v51; // [xsp+40h] [xbp-1A0h]
141 | void *v52; // [xsp+50h] [xbp-190h]
142 | __int64 v53; // [xsp+60h] [xbp-180h]
143 | __int64 v54; // [xsp+68h] [xbp-178h]
144 | void *v55; // [xsp+A0h] [xbp-140h]
145 | YYWAWebView *v56; // [xsp+A8h] [xbp-138h]
146 | __int128 v57; // [xsp+B0h] [xbp-130h]
147 | __int128 v58; // [xsp+C0h] [xbp-120h]
148 | __int128 v59; // [xsp+D0h] [xbp-110h]
149 | __int128 v60; // [xsp+E0h] [xbp-100h]
150 | char v61; // [xsp+F0h] [xbp-F0h]
151 | __int64 v62; // [xsp+170h] [xbp-70h]
152 | CGPoint v63; // 0:d0.8,8:d1.8
153 |
154 | v5 = a4.var1;
155 | v6 = a4.var0;
156 | v7 = self;
157 | v8 = (void *)objc_retain();
158 | v9 = (struct objc_object *)objc_retain();
159 | v56 = v7;
160 | if ( (unsigned int)objc_msgSend(v8, "isHidden") )
161 | goto LABEL_15;
162 | ((void (__cdecl *)(YYWAWebView *, SEL))objc_msgSend)(v7, "nativeDelegate");
163 | v10 = (void *)objc_retainAutoreleasedReturnValue();
164 | v11 = (unsigned __int64)objc_msgSend(v10, "isSelectableText:", v8);
165 | objc_release(v10);
166 | if ( v11 )
167 | {
168 | if ( (unsigned int)objc_msgSend(v8, "pointInside:withEvent:", v9, v6, v5) )
169 | {
170 | v12 = objc_retain();
171 | v13 = "setIsHitSelectableText:";
172 | LABEL_8:
173 | objc_msgSend(v7, v13, 1LL);
174 | goto LABEL_16;
175 | }
176 | goto LABEL_15;
177 | }
178 | ((void (__cdecl *)(YYWAWebView *, SEL))objc_msgSend)(v7, "nativeDelegate");
179 | v14 = (void *)objc_retainAutoreleasedReturnValue();
180 | objc_msgSend(v14, "getContainerViewFromNative:", v8);
181 | v15 = objc_retainAutoreleasedReturnValue();
182 | objc_release(v15);
183 | objc_release(v14);
184 | if ( v15 )
185 | {
186 | objc_msgSend(v8, "hitTest:withEvent:", v9, v6, v5);
187 | v12 = objc_retainAutoreleasedReturnValue();
188 | if ( !v12 )
189 | goto LABEL_16;
190 | v13 = "setIsHitTongCeng:";
191 | goto LABEL_8;
192 | }
193 | objc_msgSend(v8, "subviews");
194 | v16 = (void *)objc_retainAutoreleasedReturnValue();
195 | v17 = (char *)objc_msgSend(v16, "count");
196 | objc_release(v16);
197 | if ( !v17 )
198 | {
199 | LABEL_14:
200 | ((void (__cdecl *)(YYWAWebView *, SEL))objc_msgSend)(v7, "wkHitView");
201 | v21 = objc_retainAutoreleasedReturnValue();
202 | objc_release(v21);
203 | if ( (void *)v21 == v8 )
204 | {
205 | v12 = objc_retain();
206 | goto LABEL_16;
207 | }
208 | LABEL_15:
209 | v12 = 0LL;
210 | goto LABEL_16;
211 | }
212 | v18 = (signed __int64)(v17 - 1);
213 | while ( 1 )
214 | {
215 | objc_msgSend(v8, "subviews");
216 | v19 = (void *)objc_retainAutoreleasedReturnValue();
217 | objc_msgSend(v19, "objectAtIndex:", v18);
218 | v20 = (struct objc_object *)objc_retainAutoreleasedReturnValue();
219 | objc_release(v19);
220 | if ( v20 )
221 | {
222 | objc_msgSend(v20, "convertPoint:fromView:", v8, v6, v5);
223 | ((void (__cdecl *)(YYWAWebView *, SEL, id, CGPoint, id))objc_msgSend)(
224 | v7,
225 | "hitWKWebNativeTest:point:withEvent:",
226 | v20,
227 | v63,
228 | v9);
229 | v12 = objc_retainAutoreleasedReturnValue();
230 | objc_release(v20);
231 | if ( v12 )
232 | break;
233 | }
234 | if ( --v18 == -1 )
235 | goto LABEL_14;
236 | }
237 | LABEL_16:
238 | objc_msgSend(v8, "superview");
239 | v22 = objc_retainAutoreleasedReturnValue();
240 | objc_msgSend(v7, "scrollView");
241 | v23 = objc_retainAutoreleasedReturnValue();
242 | v24 = v23;
243 | if ( v22 == v23 )
244 | {
245 | v25 = objc_msgSend(v8, "class");
246 | NSStringFromClass(v25);
247 | v26 = (void *)objc_retainAutoreleasedReturnValue();
248 | v27 = (unsigned __int64)objc_msgSend(v26, "isEqualToString:", CFSTR("WKContentView"));
249 | objc_release(v26);
250 | objc_release(v24);
251 | objc_release(v22);
252 | if ( v27 )
253 | {
254 | v54 = NSClassFromString(CFSTR("UITapAndAHalfRecognizer"), v28);
255 | v51 = objc_msgSend(&OBJC_CLASS___UILongPressGestureRecognizer, "class", v12, v9);
256 | v57 = 0u;
257 | v58 = 0u;
258 | v59 = 0u;
259 | v60 = 0u;
260 | v50 = v8;
261 | objc_msgSend(v8, "gestureRecognizers");
262 | v52 = (void *)objc_retainAutoreleasedReturnValue();
263 | v29 = v56;
264 | v55 = objc_msgSend(v52, "countByEnumeratingWithState:objects:count:", &v57, &v61, 16LL);
265 | if ( v55 )
266 | {
267 | v53 = *(_QWORD *)v58;
268 | do
269 | {
270 | v30 = 0LL;
271 | do
272 | {
273 | if ( *(_QWORD *)v58 != v53 )
274 | objc_enumerationMutation(v52);
275 | v31 = *(void **)(*((_QWORD *)&v57 + 1) + 8 * v30);
276 | objc_msgSend(*(void **)(*((_QWORD *)&v57 + 1) + 8 * v30), "setCancelsTouchesInView:", 0LL);
277 | objc_msgSend(v31, "setDelaysTouchesBegan:", 0LL);
278 | objc_msgSend(v31, "setDelaysTouchesEnded:", 0LL);
279 | objc_msgSend(&OBJC_CLASS___NSValue, "valueWithNonretainedObject:", v31);
280 | v32 = objc_retainAutoreleasedReturnValue();
281 | v33 = objc_msgSend(v31, "isEnabled");
282 | objc_msgSend(&OBJC_CLASS___NSNumber, "numberWithBool:", v33);
283 | v34 = objc_retainAutoreleasedReturnValue();
284 | ((void (__cdecl *)(YYWAWebView *, SEL))objc_msgSend)(v29, "gestureEnableDic");
285 | v35 = (void *)objc_retainAutoreleasedReturnValue();
286 | objc_msgSend(v35, "objectForKey:", v32);
287 | v36 = (void *)objc_retainAutoreleasedReturnValue();
288 | v37 = v35;
289 | v29 = v56;
290 | objc_release(v37);
291 | if ( (unsigned int)objc_msgSend(v31, "isKindOfClass:", v54) )
292 | {
293 | if ( (unsigned int)-[YYWAWebView isHitTongCeng](v56, "isHitTongCeng") )
294 | {
295 | if ( !v36 )
296 | {
297 | ((void (__cdecl *)(YYWAWebView *, SEL))objc_msgSend)(v56, "gestureEnableDic");
298 | v38 = (void *)objc_retainAutoreleasedReturnValue();
299 | objc_msgSend(v38, "setObject:forKey:", v34, v32);
300 | v39 = v38;
301 | v29 = v56;
302 | objc_release(v39);
303 | }
304 | objc_msgSend(v31, "setEnabled:", 0LL);
305 | }
306 | else if ( v36 )
307 | {
308 | v40 = objc_msgSend(v36, "boolValue");
309 | objc_msgSend(v31, "setEnabled:", v40);
310 | ((void (__cdecl *)(YYWAWebView *, SEL))objc_msgSend)(v56, "gestureEnableDic");
311 | v41 = (void *)objc_retainAutoreleasedReturnValue();
312 | objc_msgSend(v41, "removeObjectForKey:", v32);
313 | v42 = v41;
314 | v29 = v56;
315 | objc_release(v42);
316 | }
317 | }
318 | if ( (unsigned int)+[DeviceInfo isiOS11plus](&OBJC_CLASS___DeviceInfo, "isiOS11plus")
319 | && (unsigned int)objc_msgSend(v31, "isKindOfClass:", v51) )
320 | {
321 | if ( (unsigned int)-[YYWAWebView isHitSelectableText](v29, "isHitSelectableText") )
322 | {
323 | if ( v36 )
324 | {
325 | v43 = objc_msgSend(v36, "boolValue");
326 | objc_msgSend(v31, "setEnabled:", v43);
327 | ((void (__cdecl *)(YYWAWebView *, SEL))objc_msgSend)(v29, "gestureEnableDic");
328 | v44 = (void *)objc_retainAutoreleasedReturnValue();
329 | objc_msgSend(v44, "removeObjectForKey:", v32);
330 | objc_release(v44);
331 | }
332 | }
333 | else
334 | {
335 | if ( !v36 )
336 | {
337 | ((void (__cdecl *)(YYWAWebView *, SEL))objc_msgSend)(v29, "gestureEnableDic");
338 | v45 = (void *)objc_retainAutoreleasedReturnValue();
339 | objc_msgSend(v45, "setObject:forKey:", v34, v32);
340 | v46 = v45;
341 | v29 = v56;
342 | objc_release(v46);
343 | }
344 | objc_msgSend(v31, "setEnabled:", 0LL);
345 | }
346 | }
347 | objc_release(v36);
348 | objc_release(v34);
349 | objc_release(v32);
350 | ++v30;
351 | }
352 | while ( v30 < (unsigned __int64)v55 );
353 | v55 = objc_msgSend(v52, "countByEnumeratingWithState:objects:count:", &v57, &v61, 16LL);
354 | }
355 | while ( v55 );
356 | }
357 | objc_release(v52);
358 | v9 = v49;
359 | v8 = v50;
360 | v12 = v48;
361 | }
362 | }
363 | else
364 | {
365 | objc_release(v23);
366 | objc_release(v22);
367 | }
368 | objc_release(v9);
369 | result = (id)objc_release(v8);
370 | if ( __stack_chk_guard == v62 )
371 | result = (id)objc_autoreleaseReturnValue(v12);
372 | return result;
373 | }
374 |
--------------------------------------------------------------------------------
/WeAppTongCeng/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/11.
6 | //
7 |
8 | #import
9 |
10 | @interface ViewController : UIViewController
11 |
12 |
13 | @end
14 |
15 |
--------------------------------------------------------------------------------
/WeAppTongCeng/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/11.
6 | //
7 |
8 | #import "ViewController.h"
9 |
10 | @interface ViewController ()
11 |
12 | @end
13 |
14 | @implementation ViewController
15 |
16 | - (void)viewDidLoad {
17 | [super viewDidLoad];
18 | // Do any additional setup after loading the view.
19 | }
20 |
21 | - (IBAction)toWKWebViewVC:(id)sender {
22 | [self.navigationController pushViewController:NSClassFromString(@"LVWKWebController").new animated:YES];
23 | }
24 |
25 | - (IBAction)toTongCengWebViewVC:(id)sender {
26 | [self.navigationController pushViewController:NSClassFromString(@"LVTongCengWebController").new animated:YES];
27 | }
28 |
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/WeAppTongCeng/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // WeAppTongCeng
4 | //
5 | // Created by wulinfeng on 2021/3/11.
6 | //
7 |
8 | #import
9 | #import "AppDelegate.h"
10 |
11 | int main(int argc, char * argv[]) {
12 | NSString * appDelegateClassName;
13 | @autoreleasepool {
14 | // Setup code that might create autoreleased objects goes here.
15 | appDelegateClassName = NSStringFromClass([AppDelegate class]);
16 | }
17 | return UIApplicationMain(argc, argv, nil, appDelegateClassName);
18 | }
19 |
--------------------------------------------------------------------------------
/WeAppTongCeng/test/LVTongCengWebController.h:
--------------------------------------------------------------------------------
1 | //
2 | // LVTongCengWebController.h
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/12.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface LVTongCengWebController : UIViewController
13 |
14 | @end
15 |
16 | NS_ASSUME_NONNULL_END
17 |
--------------------------------------------------------------------------------
/WeAppTongCeng/test/LVTongCengWebController.m:
--------------------------------------------------------------------------------
1 | //
2 | // LVTongCengWebController.m
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/12.
6 | //
7 |
8 | #import "LVTongCengWebController.h"
9 | #import "LVTongCengWebView.h"
10 | #import "LVWebViewBridge.h"
11 | #import "LVTongCengWebMgr.h"
12 |
13 | @interface LVTongCengWebController ()
14 | @property (strong, nonatomic) WKWebView *webView;
15 | @property (strong, nonatomic) LVTongCengWebMgr *tongCengWebMgr;
16 | @property (strong, nonatomic) LVWebViewBridge *webBridge;
17 | @end
18 |
19 | @implementation LVTongCengWebController
20 |
21 | - (void)viewDidLoad {
22 | [super viewDidLoad];
23 | self.view.backgroundColor = UIColor.whiteColor;
24 | self.title = @"TongCeng WebView";
25 |
26 | self.tongCengWebMgr = [[LVTongCengWebMgr alloc] init];
27 | self.webBridge = [[LVWebViewBridge alloc] initWithDelegate:self.tongCengWebMgr];
28 |
29 | WKWebView *webView = [[[self webViewClass] alloc] initWithFrame:self.view.bounds configuration:[self.webBridge genBridgeOfWKUserContentController]];
30 | [self.view addSubview:webView];
31 | NSString *htmlPath = [[NSBundle mainBundle] pathForResource:@"tongceng.html" ofType:nil];
32 | NSString *html = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil];
33 | [webView loadHTMLString:html baseURL:nil];
34 | self.webView = webView;
35 | }
36 |
37 | - (Class)webViewClass {
38 | return LVTongCengWebView.class;
39 | }
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/WeAppTongCeng/test/LVWKWebController.h:
--------------------------------------------------------------------------------
1 | //
2 | // LVWKWebController.h
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/16.
6 | //
7 |
8 | #import "LVTongCengWebController.h"
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface LVWKWebController : LVTongCengWebController
13 |
14 | @end
15 |
16 | NS_ASSUME_NONNULL_END
17 |
--------------------------------------------------------------------------------
/WeAppTongCeng/test/LVWKWebController.m:
--------------------------------------------------------------------------------
1 | //
2 | // LVWKWebController.m
3 | // WeAppTongCeng
4 | //
5 | // Created by lionvoom on 2021/3/16.
6 | //
7 |
8 | #import "LVWKWebController.h"
9 |
10 | @interface LVWKWebController ()
11 |
12 | @end
13 |
14 | @implementation LVWKWebController
15 |
16 | - (void)viewDidLoad {
17 | [super viewDidLoad];
18 | self.title = @"WKWebView(native no respond)";
19 | }
20 |
21 | - (Class)webViewClass {
22 | return NSClassFromString(@"WKWebView");
23 | }
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/WeAppTongCeng/test/LVWebViewBridge/LVBridge.h:
--------------------------------------------------------------------------------
1 | //
2 | // LVBridge.h
3 | // WeAppTongCeng
4 | //
5 | // Created by wulinfeng on 2021/3/16.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface LVWebViewBridge : NSObject
13 |
14 | @end
15 |
16 | NS_ASSUME_NONNULL_END
17 |
--------------------------------------------------------------------------------
/WeAppTongCeng/test/LVWebViewBridge/LVTongCengWebManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // LVTongCengWebManager.h
3 | // WeAppTongCeng
4 | //
5 | // Created by wulinfeng on 2021/3/16.
6 | //
7 |
8 | #import
9 | #import "LVTongCengWebDelegate-Protocol.h"
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface LVTongCengWebMgr : NSObject
14 |
15 | @end
16 |
17 | NS_ASSUME_NONNULL_END
18 |
--------------------------------------------------------------------------------
/WeAppTongCeng/test/tongceng.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 同层渲染测试
7 |
8 |
65 |
66 |
67 |
68 |
69 |
70 |
73 |
76 |
79 | more content
80 |
81 |
82 |
83 |
84 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/WeAppTongCengTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/WeAppTongCengTests/WeAppTongCengTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // WeAppTongCengTests.m
3 | // WeAppTongCengTests
4 | //
5 | // Created by lionvoom on 2021/3/11.
6 | //
7 |
8 | #import
9 |
10 | @interface WeAppTongCengTests : XCTestCase
11 |
12 | @end
13 |
14 | @implementation WeAppTongCengTests
15 |
16 | - (void)setUp {
17 | // Put setup code here. This method is called before the invocation of each test method in the class.
18 | }
19 |
20 | - (void)tearDown {
21 | // Put teardown code here. This method is called after the invocation of each test method in the class.
22 | }
23 |
24 | - (void)testExample {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | - (void)testPerformanceExample {
30 | // This is an example of a performance test case.
31 | [self measureBlock:^{
32 | // Put the code you want to measure the time of here.
33 | }];
34 | }
35 |
36 | @end
37 |
--------------------------------------------------------------------------------
/WeAppTongCengUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/WeAppTongCengUITests/WeAppTongCengUITests.m:
--------------------------------------------------------------------------------
1 | //
2 | // WeAppTongCengUITests.m
3 | // WeAppTongCengUITests
4 | //
5 | // Created by lionvoom on 2021/3/11.
6 | //
7 |
8 | #import
9 |
10 | @interface WeAppTongCengUITests : XCTestCase
11 |
12 | @end
13 |
14 | @implementation WeAppTongCengUITests
15 |
16 | - (void)setUp {
17 | // Put setup code here. This method is called before the invocation of each test method in the class.
18 |
19 | // In UI tests it is usually best to stop immediately when a failure occurs.
20 | self.continueAfterFailure = NO;
21 |
22 | // 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.
23 | }
24 |
25 | - (void)tearDown {
26 | // Put teardown code here. This method is called after the invocation of each test method in the class.
27 | }
28 |
29 | - (void)testExample {
30 | // UI tests must launch the application that they test.
31 | XCUIApplication *app = [[XCUIApplication alloc] init];
32 | [app launch];
33 |
34 | // Use recording to get started writing UI tests.
35 | // Use XCTAssert and related functions to verify your tests produce the correct results.
36 | }
37 |
38 | - (void)testLaunchPerformance {
39 | if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) {
40 | // This measures how long it takes to launch your application.
41 | [self measureWithMetrics:@[[[XCTApplicationLaunchMetric alloc] init]] block:^{
42 | [[[XCUIApplication alloc] init] launch];
43 | }];
44 | }
45 | }
46 |
47 | @end
48 |
--------------------------------------------------------------------------------