@@ -13,99 +13,118 @@ giving them access to all properties, methods, and events of
13
13
[ CoreWebView2Frame] ( https://learn.microsoft.com/dotnet/api/microsoft.web.webview2.core.corewebview2frame )
14
14
for the nested iframe.
15
15
16
- To prevent unnecessary performance implication, WebView2 does
17
- not track any nested iframes by default. It only tracks a nested
18
- iframe if its parent iframe (` CoreWebView2Frame ` ) has subscribed
19
- to the ` CoreWebView2Frame.FrameCreated ` API. For a page with
20
- multi-level iframes, developers can choose to track only the
21
- main page and first-level iframes (the default behavior), a
22
- partial WebView2 frames tree with specific iframes of interest,
23
- or the full WebView2 frames tree.
16
+ With the new API, developers can manage iframe tracking on a page
17
+ contains multiple levels of iframes. They can choose track only the
18
+ main page and first-level iframes (the default behavior), a partial
19
+ WebView2 frames tree with specific iframes of interest, or the full
20
+ WebView2 frames tree.
24
21
25
22
# Examples
23
+ ## Track partial WebView2 Frames Tree
26
24
### C++ Sample
27
- ``` cpp
25
+ ``` cpp
28
26
wil::com_ptr<ICoreWebView2> m_webview;
29
- std::map<int , std::vector<std::wstring>> m_frame_navigation_urls;
30
- // In this example, a WebView2 application wants to manage the
31
- // navigation of third-party content residing in second-level iframes
27
+ std::map<UINT32 , std::vector<std::wstring>> m_frame_navigation_urls;
28
+ // In this example, we present a scenario where a WebView2 application wants to
29
+ // manage the navigation of third-party content residing in second-level iframes
32
30
// (Main frame -> First-level frame -> Second-level third-party frames).
33
- HRESULT RecordThirdPartyFrameNavigation () {
31
+ void TrackThirdPartyFrameNavigations ()
32
+ {
34
33
auto webview2_4 = m_webView.try_query<ICoreWebView2_4>();
35
- // Track the first-level webview frame.
36
- webview2_4->add_FrameCreated(
34
+ if (webview2_4)
35
+ {
36
+ webview2_4->add_FrameCreated(
37
37
Callback<ICoreWebView2FrameCreatedEventHandler>(
38
- [this](ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args)
39
- -> HRESULT {
38
+ [this](ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args)
39
+ noexcept -> HRESULT
40
+ {
40
41
// [AddFrameCreated]
41
42
wil::com_ptr<ICoreWebView2Frame> webviewFrame;
42
43
CHECK_FAILURE (args->get_Frame(&webviewFrame));
44
+
43
45
// Track nested (second-level) webview frame.
44
46
auto frame7 = webviewFrame.try_query<ICoreWebView2Frame7>();
45
- frame7->add_FrameCreated(
46
- Callback<ICoreWebView2FrameChildFrameCreatedEventHandler >(
47
- [ this] (
48
- ICoreWebView2Frame* sender,
49
- ICoreWebView2FrameCreatedEventArgs* args) -> HRESULT
50
- {
51
- wil::com_ptr<ICoreWebView2Frame > webviewFrame;
52
- CHECK_FAILURE(args->get_Frame(&webviewFrame));
53
- wil::com_ptr<ICoreWebView2Frame2 > frame2 =
54
- webviewFrame.try_query<ICoreWebView2Frame2 >();
55
- if (frame2)
47
+ if (frame7)
48
+ {
49
+ frame7->add_FrameCreated(
50
+ Callback<ICoreWebView2FrameChildFrameCreatedEventHandler>(
51
+ [this](
52
+ ICoreWebView2Frame* sender,
53
+ ICoreWebView2FrameCreatedEventArgs* args) noexcept
54
+ -> HRESULT
56
55
{
57
- // Subscribe to nested (second-level) webview frame navigation
58
- // starting event.
59
- frame2->add_NavigationStarting(
60
- Callback<ICoreWebView2FrameNavigationStartingEventHandler >(
61
- [ this] (
62
- ICoreWebView2Frame* sender,
63
- ICoreWebView2NavigationStartingEventArgs* args) -> HRESULT {
64
- // Manage the navigation, e.g. cancel the
65
- // navigation if it's on block list.
66
- UINT32 frameId = 0;
67
- auto frame5 = wil::com_ptr<ICoreWebView2Frame >(sender)
68
- .try_query<ICoreWebView2Frame5 >();
69
- CHECK_FAILURE(frame5->get_FrameId(&frameId));
70
- wil::unique_cotaskmem_string uri;
71
- CHECK_FAILURE(args->get_Uri(&uri));
72
- // Log the navigation history per frame Id.
73
- m_frame_navigation_urls[ (int)frameId] .push_back(uri.get());
74
- return S_OK;
75
- })
76
- .Get(),
77
- nullptr);
78
- }
79
- return S_OK;
80
- })
81
- .Get(),
82
- nullptr);
56
+ wil::com_ptr<ICoreWebView2Frame> webviewFrame;
57
+ CHECK_FAILURE (args->get_Frame(&webviewFrame));
58
+
59
+ wil::com_ptr<ICoreWebView2Frame2> frame2 =
60
+ webviewFrame.try_query<ICoreWebView2Frame2>();
61
+ if (frame2)
62
+ {
63
+ // Subscribe to nested (second-level) webview frame
64
+ // navigation starting event.
65
+ frame2->add_NavigationStarting(
66
+ Callback<
67
+ ICoreWebView2FrameNavigationStartingEventHandler>(
68
+ [this](
69
+ ICoreWebView2Frame* sender,
70
+ ICoreWebView2NavigationStartingEventArgs* args)
71
+ noexcept -> HRESULT
72
+ {
73
+ // Manage the navigation, e.g. cancel the
74
+ // navigation if it's on block list.
75
+
76
+ UINT32 frameId = 0;
77
+ auto frame5 =
78
+ wil::try_query<ICoreWebView2Frame5>(sender);
79
+ if (frame5)
80
+ {
81
+ CHECK_FAILURE (
82
+ frame5->get_FrameId(&frameId));
83
+ }
84
+ wil::unique_cotaskmem_string uri;
85
+ CHECK_FAILURE (args->get_Uri(&uri));
86
+
87
+ // Log the navigation history per frame Id.
88
+ m_frame_navigation_urls[frameId].push_back(uri.get());
89
+ return S_OK;
90
+ })
91
+ .Get(),
92
+ nullptr);
93
+ }
94
+ return S_OK;
95
+ })
96
+ .Get(),
97
+ nullptr);
98
+ }
83
99
// [AddFrameCreated]
84
100
return S_OK;
85
101
})
86
102
.Get(),
87
- nullptr);
103
+ nullptr);
104
+ }
88
105
}
106
+
89
107
```
90
108
### C# Sample
91
109
``` c#
92
110
var _frameNavigationUrls = new Dictionary <UINT32 , List <string >>();
93
- // In this example, a WebView2 application wants to manage the
94
- // navigation of third-party content residing in second-level iframes
111
+ // In this example, we present a scenario where a WebView2 application wants to
112
+ // manage the navigation of third-party content residing in second-level iframes
95
113
// (Main frame -> First-level frame -> second-level third-party frames).
96
- void RecordThirdPartyFrameNavigation () {
114
+ void TrackThirdPartyFrameNavigations ()
115
+ {
97
116
webView .CoreWebView2 .FrameCreated += (sender , args ) =>
98
117
{
99
118
// Track nested (second-level) webview frame.
100
119
args .Frame .FrameCreated += (frameCreatedSender , frameCreatedArgs ) =>
101
120
{
102
121
CoreWebView2Frame childFrame = frameCreatedArgs .Frame ;
103
- childFrame .NavigationStarting += HandleChildFrameNavigationStarting ;
104
- }
105
- }
122
+ childFrame .NavigationStarting += OnFrameNavigationStarting ;
123
+ };
124
+ };
106
125
}
107
126
108
- void HandleChildFrameNavigationStarting (object sender ,
127
+ void OnFrameNavigationStarting (object sender ,
109
128
CoreWebView2NavigationStartingEventArgs args )
110
129
{
111
130
// Manage the navigation, e.g. cancel the navigation
@@ -120,6 +139,123 @@ void HandleChildFrameNavigationStarting(object sender,
120
139
}
121
140
```
122
141
142
+ ## Track entire WebView2 Frames Tree
143
+ ### C++ Sample
144
+ ``` C++
145
+ wil::com_ptr<ICoreWebView2> m_webview;
146
+ std::map<UINT32, std::vector<std::wstring>> m_frame_navigation_urls;
147
+ void OnFrameCreated (wil::com_ptr<ICoreWebView2Frame > webviewFrame);
148
+ // In this example, we present a scenario where a WebView2 application
149
+ // wants to manage the navigation in all iframes.
150
+ void TrackAllFrameNavigations()
151
+ {
152
+ auto webview2_4 = m_webview.try_query<ICoreWebView2_4>();
153
+ if (webview2_4)
154
+ {
155
+ webview2_4->add_FrameCreated(
156
+ Callback<ICoreWebView2FrameCreatedEventHandler >(
157
+ [ this] (ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args)
158
+ noexcept -> HRESULT
159
+ {
160
+ wil::com_ptr<ICoreWebView2Frame > webviewFrame;
161
+ CHECK_FAILURE(args->get_Frame(&webviewFrame));
162
+ // Track first-level webview frame.
163
+ OnFrameCreated(webviewFrame);
164
+ return S_OK;
165
+ })
166
+ .Get(),
167
+ nullptr);
168
+ }
169
+ }
170
+
171
+ void OnFrameCreated(wil::com_ptr<ICoreWebView2Frame > webviewFrame)
172
+ {
173
+ auto frame7 = webviewFrame.try_query<ICoreWebView2Frame7 >();
174
+ if (frame7)
175
+ {
176
+ //! [ AddFrameCreated]
177
+ frame7->add_FrameCreated(
178
+ Callback<ICoreWebView2FrameChildFrameCreatedEventHandler >(
179
+ [ this] (
180
+ ICoreWebView2Frame* sender,
181
+ ICoreWebView2FrameCreatedEventArgs* args) noexcept -> HRESULT
182
+ {
183
+ wil::com_ptr<ICoreWebView2Frame > webviewFrame;
184
+ CHECK_FAILURE(args->get_Frame(&webviewFrame));
185
+ // Make a recursive call to track all nested
186
+ // webview frame.
187
+ OnFrameCreated(webviewFrame);
188
+ return S_OK;
189
+ })
190
+ .Get(),
191
+ nullptr);
192
+ //! [ AddFrameCreated]
193
+ }
194
+
195
+ // Subscribe to webview frame navigation starting event.
196
+ wil::com_ptr<ICoreWebView2Frame2> frame2 = webviewFrame.try_query<ICoreWebView2Frame2>();
197
+ if (frame2)
198
+ {
199
+ frame2->add_NavigationStarting(
200
+ Callback<ICoreWebView2FrameNavigationStartingEventHandler>(
201
+ [this](
202
+ ICoreWebView2Frame* sender,
203
+ ICoreWebView2NavigationStartingEventArgs* args) noexcept -> HRESULT
204
+ {
205
+ // Manage the navigation, e.g. cancel the
206
+ // navigation if it's on block list.
207
+
208
+ UINT32 frameId = 0;
209
+ auto frame5 = wil::try_query<ICoreWebView2Frame5>(sender);
210
+ if (frame5)
211
+ {
212
+ CHECK_FAILURE(frame5->get_FrameId(&frameId));
213
+ }
214
+ wil::unique_cotaskmem_string uri;
215
+ CHECK_FAILURE(args->get_Uri(&uri));
216
+
217
+ // Log the navigation history per frame Id.
218
+ m_frame_navigation_urls[frameId].push_back(uri.get());
219
+ return S_OK;
220
+ })
221
+ .Get(),
222
+ nullptr);
223
+ }
224
+ }
225
+ ```
226
+
227
+ ### C# Sample
228
+ ```C#
229
+ var _frameNavigationUrls = new Dictionary<UINT32, List<string>>();
230
+ // In this example, we present a scenario where a WebView2 application
231
+ // wants to manage the navigation in all iframes.
232
+ void TrackAllFrameNavigations(object target, ExecutedRoutedEventArgs e)
233
+ {
234
+ webView.CoreWebView2.FrameCreated += OnFrameCreated;
235
+ }
236
+
237
+ void OnFrameCreated(object sender, CoreWebView2FrameCreatedEventArgs args)
238
+ {
239
+ CoreWebView2Frame childFrame = args.Frame;
240
+ // Make a recursive call to track all nested webview frames event.
241
+ childFrame.FrameCreated += OnFrameCreated;
242
+ childFrame.NavigationStarting += OnFrameNavigationStarting;
243
+ }
244
+
245
+ void OnFrameNavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs args)
246
+ {
247
+ // Manage the navigation, e.g. cancel the navigation
248
+ // if it's on block list.
249
+ CoreWebView2Frame frame = (CoreWebView2Frame)sender;
250
+ if (!_frameNavigationUrls.ContainsKey(frame.FrameId))
251
+ {
252
+ _frameNavigationUrls[frame.FrameId] = new List<string>();
253
+ }
254
+ // Log the navigation history per frame Id.
255
+ _frameNavigationUrls[frame.FrameId].Add(args.Uri);
256
+ }
257
+ ```
258
+
123
259
# API Details
124
260
## C++
125
261
``` C++
@@ -186,16 +322,17 @@ to the frame that initiates the request (from bottom to top).
186
322
```
187
323
Suppose there's a ` PermissionRequest ` comes from D.
188
324
* If D is a tracked frame (` CoreWebView2Frame ` ), then D is the
189
- closet tracked frame from which the request will be raised from.
325
+ closest tracked frame from which the request will be raised from.
190
326
* If D is not being tracked, and C is a tracked frame. Then C
191
- is the closet tracked frame from which the request will be
327
+ is the closest tracked frame from which the request will be
192
328
raised from.
193
- * If neither C nor D is tracked, then B is the closet tracked
329
+ * If neither C nor D is tracked, then B is the closest tracked
194
330
frame from which the request will be raised. This case applies
195
331
to current ` PermissionRequested ` developers, as they haven't
196
- subscribe to the ` CoreWebView2Frame.FrameCreated ` event.
197
- Therefore, requests originating from iframes will still be
198
- raised from the first-level iframe.
332
+ subscribed to the ` CoreWebView2Frame.FrameCreated ` event.
333
+ Consequently, there is no change in behavior, and requests
334
+ originating from iframes will continue to be raised from the
335
+ first-level iframe.
199
336
200
337
If the ` PermissionRequested ` event is not handled in the current
201
338
tracked frame, the request will propagate to its parent
@@ -211,5 +348,5 @@ which support these nested iframes will be also tracked by
211
348
[ ProcessFailed] ( https://learn.microsoft.com/dotnet/api/microsoft.web.webview2.core.corewebview2.processfailed ) .
212
349
As we only track processes running tracked iframes, existing
213
350
developers will not receive any process failed events specific
214
- to nested iframes as they haven't subscribe to the
351
+ to nested iframes as they haven't subscribed to the
215
352
` CoreWebView2Frame.FrameCreated ` event.
0 commit comments