@@ -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 )
1414for 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
2826wil::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#
92110var _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```
187323Suppose 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
192328raised 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
194330frame from which the request will be raised. This case applies
195331to 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
200337If the ` PermissionRequested ` event is not handled in the current
201338tracked 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 ) .
212349As we only track processes running tracked iframes, existing
213350developers 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