Skip to content

Commit 4d00028

Browse files
author
Wangsong Jin
committed
addressed comments from API review meeting
1 parent 2e237f6 commit 4d00028

File tree

1 file changed

+206
-69
lines changed

1 file changed

+206
-69
lines changed

specs/NestedFrame.md

Lines changed: 206 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -13,99 +13,118 @@ giving them access to all properties, methods, and events of
1313
[CoreWebView2Frame](https://learn.microsoft.com/dotnet/api/microsoft.web.webview2.core.corewebview2frame)
1414
for the nested iframe.
1515

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.
2421

2522
# Examples
23+
## Track partial WebView2 Frames Tree
2624
### C++ Sample
27-
```cpp
25+
```cpp
2826
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
3230
// (Main frame -> First-level frame -> Second-level third-party frames).
33-
HRESULT RecordThirdPartyFrameNavigation() {
31+
void TrackThirdPartyFrameNavigations()
32+
{
3433
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(
3737
Callback<ICoreWebView2FrameCreatedEventHandler>(
38-
[this](ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args)
39-
-> HRESULT {
38+
[this](ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args)
39+
noexcept -> HRESULT
40+
{
4041
// [AddFrameCreated]
4142
wil::com_ptr<ICoreWebView2Frame> webviewFrame;
4243
CHECK_FAILURE(args->get_Frame(&webviewFrame));
44+
4345
// Track nested (second-level) webview frame.
4446
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
5655
{
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+
}
8399
// [AddFrameCreated]
84100
return S_OK;
85101
})
86102
.Get(),
87-
nullptr);
103+
nullptr);
104+
}
88105
}
106+
89107
```
90108
### C# Sample
91109
```c#
92110
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
95113
// (Main frame -> First-level frame -> second-level third-party frames).
96-
void RecordThirdPartyFrameNavigation() {
114+
void TrackThirdPartyFrameNavigations()
115+
{
97116
webView.CoreWebView2.FrameCreated += (sender, args) =>
98117
{
99118
// Track nested (second-level) webview frame.
100119
args.Frame.FrameCreated += (frameCreatedSender, frameCreatedArgs) =>
101120
{
102121
CoreWebView2Frame childFrame = frameCreatedArgs.Frame;
103-
childFrame.NavigationStarting += HandleChildFrameNavigationStarting;
104-
}
105-
}
122+
childFrame.NavigationStarting += OnFrameNavigationStarting;
123+
};
124+
};
106125
}
107126

108-
void HandleChildFrameNavigationStarting(object sender,
127+
void OnFrameNavigationStarting(object sender,
109128
CoreWebView2NavigationStartingEventArgs args)
110129
{
111130
// Manage the navigation, e.g. cancel the navigation
@@ -120,6 +139,123 @@ void HandleChildFrameNavigationStarting(object sender,
120139
}
121140
```
122141

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+
123259
# API Details
124260
## C++
125261
```C++
@@ -186,16 +322,17 @@ to the frame that initiates the request (from bottom to top).
186322
```
187323
Suppose there's a `PermissionRequest` comes from D.
188324
* 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.
190326
* 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
192328
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
194330
frame from which the request will be raised. This case applies
195331
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.
199336

200337
If the `PermissionRequested` event is not handled in the current
201338
tracked frame, the request will propagate to its parent
@@ -211,5 +348,5 @@ which support these nested iframes will be also tracked by
211348
[ProcessFailed](https://learn.microsoft.com/dotnet/api/microsoft.web.webview2.core.corewebview2.processfailed).
212349
As we only track processes running tracked iframes, existing
213350
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
215352
`CoreWebView2Frame.FrameCreated` event.

0 commit comments

Comments
 (0)