除了載入遠端內容之外,內容也可以在本機載入至 WebView2。 有數種方法可用來將本機內容載入 WebView2 控制項,包括:
- 瀏覽至檔案 URL。
- 瀏覽至 HTML 字串。
- 虛擬主機名稱對應。
- 處理事件
WebResourceRequested。
詳細內容:
選取方法
將本機內容載入 WebView2 控制項的各種方式支援下列案例:
| 案例 | 透過瀏覽至檔案 URL | 瀏覽至 HTML 字串 | 使用虛擬主機名稱對應 | 使用 WebResourceRequested |
|---|---|---|---|---|
| 以原始來源為基礎的 DOM API | 是 ✔️ | 否❌ | 是 ✔️ | 是 ✔️ |
| 需要安全內容的 DOM API | 否❌ | 否❌ | 是 ✔️ | 是 ✔️ |
| 動態內容 | 否❌ | 是 ✔️ | 否❌ | 是 ✔️ |
| 其他 Web 資源 | 是 ✔️ | 否❌ | 是 ✔️ | 是 ✔️ |
| 在 WebView2 程序中解決的其他 Web 資源 | 是 ✔️ | 否❌ | 是 ✔️ | 否❌ |
以下說明這些案例。
瀏覽至檔案 URL 以載入本機內容
WebView2 允許瀏覽至檔案 URL、載入基本的 HTML 或 PDF。 這是載入本機內容最簡單、最有效率的方法。 但是,它不如其他方法靈活。 就像在網頁瀏覽器中一樣,檔案 URL 在某些功能上受到限制:
文件的來源對於其檔案路徑而言是唯一的。 這表示需要來源
localStorage的 Web API 如 或indexedDB將可運作,但儲存的資料將無法供從其他檔案路徑載入的其他本機文件使用。某些 Web API 僅限於安全的 HTTPS URL,無法供檔案 URL 載入的文件使用。 這包括 API,例如
navigator.mediaDevices.getUserMedia()獲取視頻或聲音、navigator.geolocation.getCurrentPosition()訪問設備的位置或Notification.requestPermission()請求用戶顯示通知的權限。必須針對每個資源指定完整路徑。
若要允許從檔案 URI 參照其他本機檔案,或顯示套用 XSL 轉換的 XML 檔案,您可以設定
--allow-file-access-from-files瀏覽器引數。 請參閱 CoreWebView2EnvironmentOptions.AdditionalBrowserArguments 屬性。
透過瀏覽至檔案 URL 載入本機內容的考量
檔案 URL 的行為就像在瀏覽器中一樣。 例如,您無法在檔案 URL 中進行 XMLHttpRequest (XHR) ,因為您不是在網頁內容中作業。
您必須為每個資源指定檔案的完整路徑。 例如:
file:///C:/Users/username/Documents/GitHub/Demos/demo-to-do/index.html
跨原始來源資源
指定檔案 URL 時,應用程式會瀏覽至磁碟上的檔案,而不是網路上的網域。 因此,無法在產生的文件中使用跨原始來源資源。
以原始來源為基礎的 DOM API
透過檔案 URL 載入的文件具有其檔案路徑唯一的來源,就像在瀏覽器中一樣。 需要來源的 Web API,例如 localStorage 或 indexedDB 將可運作。 不過,從不同檔案 URL 載入的不同文件不會被視為來自同一來源,而且無法存取相同的儲存資料。
需要安全內容的 DOM API
某些 Web API 僅限於安全的 HTTPS URL,無法供檔案 URL 載入的文件使用。 這包括 API,例如 navigator.mediaDevices.getUserMedia() 獲取視頻或聲音、 navigator.geolocation.getCurrentPosition() 訪問設備的位置或 Notification.requestPermission() 請求用戶顯示通知的權限。 如需詳細資訊,請參閱 MDN 上的 安全內容 。
動態內容
透過檔案 URL 載入文件時,文件的內容來自磁碟上的靜態檔案。 這表示無法動態修改此本機內容。 這與從 Web 伺服器載入文件不同,在 Web 伺服器中,每個回應都可以動態產生。
其他 Web 資源
相對 URL 解析也適用於透過檔案 URL 載入的文件。 這表示載入的文件可以參考其他 Web 資源,例如 CSS、指令碼或影像檔案,這些資源也會透過檔案 URL 提供。
在 WebView2 程序中解決的其他 Web 資源
檔案 URL 會在 WebView2 處理序中解析。 這是比 WebResourceRequested更快的選項,可在主機應用程式處理序 UI 執行緒中解析。
透過瀏覽至檔案 URL 載入本機內容的 API
檔案 URL 範例
本節以與平台無關的方式顯示本機內容檔案路徑的檔案 URL 外觀。
WebView2 應用程式必須使用首碼和斜線撰寫 file:/// 本機檔案 URL。 例如,對於示範待辦事項範例,路徑為:
file:///C:/Users/username/Documents/GitHub/Demos/demo-to-do/index.html
若要複製本機檔案前置詞為 “file” 的完整路徑:
或者,複製 Demos 儲存庫,以獲得本機複本。 請參閱安裝 Visual Studio Code 的開發工具延伸模組中的步驟 5:複製示範存放庫。
在 Microsoft Edge 中,按 Ctrl+O 開啟檔案。 開啟本機
.html檔案,例如本機複製的檔案Demos/demo-to-do/index.html:C:\Users\username\Documents\GitHub\Demos\demo-to-do\index.html網址列一開始不會顯示
file:///首碼,而是以磁碟機代號開頭:C:/Users/username/Documents/GitHub/Demos/demo-to-do/index.html
按一下網址列,然後按 Home 鍵,或按 Ctrl+A 以選取整個路徑。
包含的整個檔案路徑
file:///會複製到剪貼簿緩衝區中,因此您可以貼上包括前置詞在內file:///的完整路徑:file:///C:/Users/username/Documents/GitHub/Demos/demo-to-do/index.html
另請參閱:
- 示範待辦事項 - 轉譯頁面
- 示範待辦事項 - 原始程式碼
- 步驟 5:在安裝 Visual Studio Code 的開發工具延伸模組中複製示範存放庫。
瀏覽至檔案 URL 的範例
webView.CoreWebView2.Navigate(
"file:///C:/Users/username/Documents/GitHub/Demos/demo-to-do/index.html");
瀏覽至 HTML 字串載入本機內容
載入本機內容的另一種方法是方法 NavigateToString 。 此方法會直接從字串將內容載入至 WebView2。 如果您要透過應用程式程式碼封裝內容,或想要以動態方式建立內容,這項功能會很有用。
瀏覽至字串可能有用的另一個案例是,如果您想要載入無法透過 URL 存取的內容。 例如,如果您有 HTML 文件的記憶體內部表示法,您可以使用方法將 NavigateToString 該內容載入到 WebView2 控制項中。 如果您想要避免在將內容載入控制項之前,先將內容寫入檔案或伺服器,這個功能就相當實用。
瀏覽至 HTML 字串載入本機內容的考量
傳遞至 NavigateToString 方法的 HTML 內容字串有 2MB 的大小限制。 當字串包含內嵌的其他資源時,可能很容易超過此大小限制。 如果超過此大小限制,則會傳回錯誤:「值不在預期範圍內」。
以原始來源為基礎的 DOM API
使用 NavigateToString 方法載入的文件會將其位置設定為 about:blank ,而其來源設定為 null。 這表示無法使用相依於所定義來源的 Web API,例如 localStorage 或 indexedDB。
需要安全內容的 DOM API
某些 Web API 僅限於安全的 HTTPS URL,而且無法供透過方法 NavigateToString 載入的文件使用,因為它們的位置設定為 about:blank。 這包括 API,例如 navigator.mediaDevices.getUserMedia() 獲取視頻或聲音、 navigator.geolocation.getCurrentPosition() 訪問設備的位置或 Notification.requestPermission() 請求用戶顯示通知的權限。 如需詳細資訊,請參閱 MDN 上的 安全內容 。
動態內容
透過 NavigateToString 方法載入本機內容時,您會直接將內容作為參數提供給方法。 這意味著您可以在運行時控制內容,並且可以在需要時動態生成內容。
其他 Web 資源
使用方法 NavigateToString 載入本機內容並無法讓生成的文件參考其他 Web 資源,例如 CSS、影像或指令碼檔案。 此方法只允許您指定 HTML 文件的字串內容。 若要從 HTML 文件參考其他 Web 資源,請使用本文所述的其他方法之一,或在 HTML 文件中內嵌表示這些額外的 Web 資源。
在 WebView2 程序中解決的其他 Web 資源
NavigateToString 如前所述,不支援其他 Web 資源。
透過瀏覽至 HTML 字串載入本機內容的 API
網頁的字串表示法範例
以下是 [示範待辦事項 ] 網頁的字串表示法。 為了便於閱讀,下列清單已新增自動換行。 實際上,這些行會串連成一條長行:
`<html lang="en"><head>\n
<meta charset="UTF-8">\n
<meta name="viewport" content="width=device-width, initial-scale=1.0">\n
<title>TODO app</title>\n
<link rel="stylesheet" href="styles/light-theme.css" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)">\n
<link rel="stylesheet" href="styles/dark-theme.css" media="(prefers-color-scheme: dark)">\n
<link rel="stylesheet" href="styles/base.css">\n
<link rel="stylesheet" href="styles/to-do-styles.css">\n
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>📋
</text></svg>">\n
</head>\n\n
<body>\n
<h1>📋 My tasks</h1>\n
<form>\n
<div class="new-task-form" tabindex="0">\n
<label for="new-task">➕ Add a task</label>\n
<input id="new-task" autocomplete="off" type="text" placeholder="Try typing 'Buy milk'" title="Click to start adding a task">\n
<input type="submit" value="➡️">\n
</div>\n
<ul id="tasks"><li class="divider">No tasks defined</li></ul>\n
</form>\n\n \x3Cscript src="to-do.js">\x3C/script>\n \n\n
</body>
</html>`
若要取得上述字串:
移至 [示範] To Do。
以滑鼠右鍵按一下網頁,然後選取 [檢查] 以開啟 DevTools。
在開發工具主 控台 中,輸入:
document.body.parentElement.outerHTML。 主 控台 會輸出網頁的字串表示法:
瀏覽至 HTML 字串的範例
// Define htmlString with the string representation of HTML as above.
webView.CoreWebView2.NavigateToString(htmlString);
使用虛擬主機名稱對應載入本機內容
在 WebView2 控制項中載入本機內容的另一種方法是使用虛擬主機名稱對應。 這涉及將本機網域名稱對應到本機資料夾,因此當 WebView2 控制項嘗試載入該網域的資源時,它會改為從指定的本機資料夾位置載入內容。 文件的來源也會是虛擬主機名稱。
此方法可讓您使用列舉來 CoreWebView2HostResourceAccessKind 指定跨原始來源存取。
由於目前的限制,使用虛擬主機名稱存取的媒體檔案載入速度可能會很慢。
使用虛擬主機名稱對應載入本機內容的考量
以原始來源為基礎的 DOM API
透過虛擬主機名稱對應載入的本機內容會產生具有 HTTP 或 HTTPS URL 以及對應來源的文件。 這表示需要原始來源 localStorage 的 Web API,例如 或 indexedDB 將可運作,以及屬於相同原始來源的其他文件將能夠使用儲存的資料。 如需詳細資訊,請參閱 MDN 上的 同源原則 。
需要安全內容的 DOM API
某些 Web API 僅限於安全的 HTTPS URL。 使用虛擬主機名稱對應可為您的本機內容提供 HTTPS URL。 這表示可以使用 API, navigator.mediaDevices.getUserMedia() 例如取得視訊或聲音、 navigator.geolocation.getCurrentPosition() 存取裝置位置或 Notification.requestPermission() 要求使用者顯示通知的權限。 如需詳細資訊,請參閱 MDN 上的 安全內容 。
動態內容
透過虛擬主機名稱對應載入本機內容時,您會將虛擬主機名稱對應至磁碟上包含靜態檔案的本機資料夾。 這表示無法動態修改此本機內容。 這與從 Web 伺服器載入文件不同,在 Web 伺服器中,每個回應都可以動態產生。
其他 Web 資源
透過虛擬主機名稱對應載入的本機內容具有支援相對 URL 解析的 HTTP 或 HTTPS URL。 這表示載入的文件可以參考其他 Web 資源,例如 CSS、指令碼或影像檔案,這些資源也透過虛擬主機名稱對應提供服務,但來源對應除外;請參閱下方具有 虛擬主機名稱對應的來源對應。
在 WebView2 程序中解決的其他 Web 資源
虛擬主機名稱 URL 會在 WebView2 處理序中解析。 這是比 WebResourceRequested更快的選項,可在主機應用程式處理序 UI 執行緒中解析。
具有虛擬主機名稱對應的來源對應
需要源映射來調試編譯內容的源代碼,包括:
- 轉譯的 JavaScript,例如 TypeScript 或縮小的 JavaScript。
- 編譯的 CSS,例如 SASS 或 SCSS。
WebView2 不會載入由使用虛擬主機名稱對應載入的內容所參考的來源對應。
例如,假設 WebView2 是透過虛擬主機名稱對應載入 main.js 。 如果參照作為main.js.map其來源對應,main.js.map將main.js不會自動載入。
若要搭配虛擬主機名稱對應使用來源對應,請在編譯內容期間產生內嵌來源對應。 內嵌來源對應會內嵌在對應的編譯檔案中。
使用虛擬主機名稱對應載入本機內容的 API
虛擬主機名稱對應範例
webView.CoreWebView2.SetVirtualHostNameToFolderMapping("demo",
"C:\Github\Demos\demo-to-do", CoreWebView2HostResourceAccessKind.DenyCors);
webView.CoreWebView2.Navigate("https://demo/index.html");
透過處理 WebResourceRequested 事件載入本機內容
在 WebView2 控制項中託管本機內容的另一個方法是依賴 WebResourceRequested 事件。 當控制項嘗試載入資源時,就會觸發此事件。 您可以使用此事件來攔截要求並提供本機內容,如 網路要求的自訂管理中所述。
WebResourceRequested 可讓您根據每個要求自訂本機內容的行為。 這表示您可以決定要攔截哪些要求並提供您自己的內容,以及讓 WebView2 控制項正常處理哪些要求。 不過,自訂行為需要更多程式碼,例如虛擬主機對應,並且需要 HTTP 知識,才能建構適當的回應。
從 WebView2 的觀點來看,資源會透過網路提供,而 WebView2 會遵循應用程式在回應中設定的標頭。 由於每個要求都需要跨處理程序通訊和處理,因此使用 WebResourceRequested 事件也比其他方法慢。
自訂配置註冊
如果您想要使用自訂配置來提出產生事件的 WebResourceRequested Web 資源要求,請參閱 WebView2 API 概觀中的自訂配置註冊。
透過處理 WebResourceRequested 事件載入本機內容的考量
以原始來源為基礎的 DOM API
透過 WebResourceRequested 載入的本機內容會導致文件具有 HTTP 或 HTTPS URL 以及對應的來源。 這表示需要原始來源 localStorage 的 Web API,例如 或 indexedDB 將可運作,以及屬於相同原始來源的其他文件將能夠使用儲存的資料。 如需詳細資訊,請參閱 MDN 上的 同源原則 。
需要安全內容的 DOM API
某些 Web API 僅限於安全的 HTTPS URL。 使用 WebResourceRequested 可讓您以您自己的本機內容取代 HTTPS URL Web 資源要求。 這表示可以使用 API, navigator.mediaDevices.getUserMedia() 例如取得視訊或聲音、 navigator.geolocation.getCurrentPosition() 存取裝置位置或 Notification.requestPermission() 要求使用者顯示通知的權限。 如需詳細資訊,請參閱 MDN 上的 安全內容 。
動態內容
透過載 WebResourceRequested入本機內容時,您可以指定要在事件處理常式中載入的本機內容。 這意味著您可以在運行時控制內容,並且可以在需要時動態生成內容。
其他 Web 資源
WebResourceRequested 修改透過 HTTP 或 HTTPS URL 載入的內容,其支援相對 URL 解析。 這表示生成的文件可以參考其他 Web 資源,例如 CSS、指令碼或影像檔案,這些資源也會透過 WebResourceRequested提供,但來源對應除外;請參閱下方的事件 來源 WebResourceRequested 對應。
在 WebView2 程序中解決的其他 Web 資源
透過檔案 URL 或虛擬主機名稱對應載入內容時,會在 WebView2 處理序中執行解析。 不過,事件 WebResourceRequested 會在主應用程式處理序的 WebView2 UI 執行緒上引發,這可能會導致結果文件載入速度變慢。
- WebView2 會先暫停載入網頁,以等候事件傳送到您的主應用程式處理程序。
- 然後 WebView2 會等候您的 UI 執行緒可用。
- 然後 WebView2 會等候您的應用程式程式碼來處理事件。
這可能需要一些時間。 請務必將呼叫 AddWebResourceRequestedFilter 限制為僅限必須引發 WebResourceRequested 事件的 Web 資源。
來源對應與 WebResourceRequested 事件
需要源映射來調試編譯內容的源代碼,包括:
- 轉譯的 JavaScript,例如 TypeScript 或縮小的 JavaScript。
- 編譯的 CSS,例如 SASS 或 SCSS。
WebView2 不會載入由使用 WebResourceRequested 事件載入之內容所參考的來源對應。
例如,假設您在事件處理常式中WebResourceRequested載入main.js,方法是將 的屬性ResponseCoreWebView2WebResourceRequestedEventArgs設定為 。 如果 main.js 參照作為 main.js.map 其來源對應:
-
main.js.map將不會自動載入。 -
WebResourceRequested事件處理常式不會再次呼叫來載入main.js.map。
若要搭配 WebResourceRequested使用來源對應和 ,請使用下列其中一種方法:
在編譯內容期間產生內嵌來源對應。 內嵌來源對應會內嵌在對應的編譯檔案中。
或者,內嵌個別來源對應至事件處理常式中
WebResourceRequested執行階段的內容。 只有當您的建置系統不支援內嵌來源對應時,才使用此方法。
透過處理 WebResourceRequested 事件載入本機內容的 API
處理 WebResourceRequested 事件的範例
// Reading of response content stream happens asynchronously, and WebView2 does not
// directly dispose the stream once it read. Therefore, use the following stream
// class, which properly disposes when WebView2 has read all data. For details, see
// [CoreWebView2 does not close stream content](https://github.com/MicrosoftEdge/WebView2Feedback/issues/2513).
class ManagedStream : Stream {
public ManagedStream(Stream s)
{
s_ = s;
}
public override bool CanRead => s_.CanRead;
public override bool CanSeek => s_.CanSeek;
public override bool CanWrite => s_.CanWrite;
public override long Length => s_.Length;
public override long Position { get => s_.Position; set => s_.Position = value; }
public override void Flush()
{
throw new NotImplementedException();
}
public override long Seek(long offset, SeekOrigin origin)
{
return s_.Seek(offset, origin);
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override int Read(byte[] buffer, int offset, int count)
{
int read = 0;
try
{
read = s_.Read(buffer, offset, count);
if (read == 0)
{
s_.Dispose();
}
}
catch
{
s_.Dispose();
throw;
}
return read;
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
private Stream s_;
}
webView.CoreWebView2.AddWebResourceRequestedFilter("https://demo/*",
CoreWebView2WebResourceContext.All);
webView.CoreWebView2.WebResourceRequested += delegate (object sender,
CoreWebView2WebResourceRequestedEventArgs args)
{
string assetsFilePath = "C:\\Demo\\" +
args.Request.Uri.Substring("https://demo/*".Length - 1);
try
{
FileStream fs = File.OpenRead(assetsFilePath);
ManagedStream ms = new ManagedStream(fs);
string headers = "";
if (assetsFilePath.EndsWith(".html"))
{
headers = "Content-Type: text/html";
}
else if (assetsFilePath.EndsWith(".jpg"))
{
headers = "Content-Type: image/jpeg";
} else if (assetsFilePath.EndsWith(".png"))
{
headers = "Content-Type: image/png";
}
else if (assetsFilePath.EndsWith(".css"))
{
headers = "Content-Type: text/css";
}
else if (assetsFilePath.EndsWith(".js"))
{
headers = "Content-Type: application/javascript";
}
args.Response = webView.CoreWebView2.Environment.CreateWebResourceResponse(
ms, 200, "OK", headers);
}
catch (Exception)
{
args.Response = webView.CoreWebView2.Environment.CreateWebResourceResponse(
null, 404, "Not found", "");
}
};
另請參閱
- 在 WebView2 API 概觀中管理載入到 WebView2 的內容
- 示範待辦事項轉譯頁面