├── .github
├── ISSUE_TEMPLATE
│ ├── bug-report.md
│ └── question.md
└── workflows
│ └── CI.yml
├── .gitignore
├── .gitmodules
├── Avalonia.WebView2.slnx
├── LICENSE
├── README.md
├── ref
├── CefGlue.Avalonia.props
└── Microsoft.Web.WebView2
│ ├── LICENSE.txt
│ ├── NOTICE.txt
│ ├── lib
│ ├── net462
│ │ ├── Microsoft.Web.WebView2.Core.dll
│ │ └── Microsoft.Web.WebView2.Core.xml
│ └── netcoreapp3.0
│ │ ├── Microsoft.Web.WebView2.Core.dll
│ │ └── Microsoft.Web.WebView2.Core.xml
│ └── runtimes
│ ├── win-arm64
│ └── native
│ │ └── WebView2Loader.dll
│ ├── win-x64
│ └── native
│ │ └── WebView2Loader.dll
│ └── win-x86
│ └── native
│ └── WebView2Loader.dll
├── res
└── screenshots
│ ├── Avalonia.WebView2.Sample.Win11.webp
│ └── Avalonia.WebView2.Sample.Win7.webp
└── src
├── .editorconfig
├── Avalonia.Ref
├── AssemblyInfo.Version.Max.cs
├── Avalonia.Desktop
│ ├── AppBuilderDesktopExtensions.cs
│ └── Avalonia.Desktop.csproj
├── Avalonia.Native
│ ├── Avalonia.Native.csproj
│ └── AvaloniaNativePlatformExtensions.cs
├── Avalonia.X11
│ ├── Avalonia.X11.csproj
│ └── AvaloniaX11PlatformExtensions.cs
└── avalonia.snk
├── Avalonia.WebView2.Sample.Mobile.Android
├── Avalonia.WebView2.Sample.Mobile.Android.csproj
├── Icon.png
├── MainActivity.cs
├── Properties
│ └── AndroidManifest.xml
└── Resources
│ ├── AboutResources.txt
│ ├── drawable-night-v31
│ └── avalonia_anim.xml
│ ├── drawable-v31
│ └── avalonia_anim.xml
│ ├── drawable
│ └── splash_screen.xml
│ ├── values-night
│ └── colors.xml
│ ├── values-v31
│ └── styles.xml
│ └── values
│ ├── colors.xml
│ └── styles.xml
├── Avalonia.WebView2.Sample.Mobile.iOS
├── AppDelegate.cs
├── Avalonia.WebView2.Sample.Mobile.iOS.csproj
├── Entitlements.plist
├── Info.plist
├── Main.cs
└── Resources
│ └── LaunchScreen.xib
├── Avalonia.WebView2.Sample.Mobile
├── App.axaml
├── App.axaml.cs
├── Assets
│ └── avalonia-logo.ico
├── Avalonia.WebView2.Sample.Mobile.csproj
├── ViewLocator.cs
├── ViewModels
│ ├── MainViewModel.cs
│ └── ViewModelBase.cs
└── Views
│ ├── MainView.axaml
│ ├── MainView.axaml.cs
│ ├── MainWindow.axaml
│ └── MainWindow.axaml.cs
├── Avalonia.WebView2.Sample
├── App.xaml
├── App.xaml.cs
├── Avalonia.WebView2.Sample.csproj
├── BCL
│ ├── MS
│ │ ├── Internal
│ │ │ └── PresentationCore
│ │ │ │ ├── SR.cs
│ │ │ │ └── SRID.cs
│ │ └── Win32
│ │ │ ├── ExternDll.cs
│ │ │ └── UnsafeNativeMethodsCLR.cs
│ └── System
│ │ └── Windows
│ │ └── MessageBox.cs
├── Common8
│ └── DomainPattern.cs
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── Program.cs
├── Properties
│ ├── PublishProfiles
│ │ └── win-x64.pubxml
│ └── app.manifest
├── WebView2Compat.xaml
└── WebView2Compat.xaml.cs
├── Avalonia.WebView2
├── Avalonia.WebView2.csproj
├── Compat
│ └── IsExternalInit.cs
├── Controls
│ ├── CoreWebView2CreationProperties.cs
│ ├── StorageService
│ │ ├── IStorageService.cs
│ │ ├── StorageItemOperate.cs
│ │ ├── StorageItemType.cs
│ │ ├── StorageItemValue.Date.cs
│ │ ├── StorageItemValue.JavaScriptStringEncode.cs
│ │ ├── StorageItemValue.ToJavaScriptString.cs
│ │ └── StorageItemValue.cs
│ ├── WebView2.Disposable.cs
│ ├── WebView2.Methods.cs
│ ├── WebView2.Properties
│ │ ├── AllowExternalDrop.cs
│ │ ├── CanGoBack.cs
│ │ ├── CanGoForward.cs
│ │ ├── Cookies.cs
│ │ ├── CreationProperties.cs
│ │ ├── DefaultBackgroundColor.cs
│ │ ├── HtmlSource.cs
│ │ ├── Source.cs
│ │ ├── Storages.cs
│ │ ├── UserAgent.cs
│ │ └── ZoomFactor.cs
│ ├── WebView2.Script.cs
│ ├── WebView2.VisualTree.cs
│ └── WebView2.cs
├── Input
│ └── WebView2KeyEventArgs.cs
├── NativeMethods.txt
└── Platforms
│ ├── CefGlue
│ └── Controls
│ │ ├── WebView2.AvaloniaCefBrowser.EventHandlers.Subscribe.cs
│ │ ├── WebView2.AvaloniaCefBrowser.EventHandlers.cs
│ │ ├── WebView2.AvaloniaCefBrowser.Events.cs
│ │ └── WebView2.cs
│ ├── CefNet
│ └── WebView2.cs
│ ├── Droid
│ └── Controls
│ │ └── WebView2.cs
│ ├── EdgeWebView2
│ ├── CefNet.Avalonia
│ │ └── Internal
│ │ │ ├── GlobalHooks.cs
│ │ │ └── WindowsHwndSource.cs
│ ├── Controls
│ │ ├── WebView2.CoreWebView2.EventHandlers.Subscribe.cs
│ │ ├── WebView2.CoreWebView2.EventHandlers.cs
│ │ ├── WebView2.CoreWebView2.Events.cs
│ │ ├── WebView2.CoreWebView2.cs
│ │ ├── WebView2.CoreWebView2Controller.cs
│ │ ├── WebView2.Focus.cs
│ │ ├── WebView2.ISupportInitialize.cs
│ │ ├── WebView2.KeyPressed.cs
│ │ ├── WebView2.SizeChanged.cs
│ │ ├── WebView2.WndProc.cs
│ │ └── WebView2.cs
│ ├── ImplicitInitGate.cs
│ ├── Input
│ │ ├── KeyInterop.cs
│ │ └── WebView2KeyEventArgs.cs
│ └── Interop
│ │ ├── IHwndHost.cs
│ │ ├── NativeMethods.Paint.cs
│ │ ├── NativeMethods.Win32Window.cs
│ │ └── NativeMethods.cs
│ ├── iOS
│ └── Controls
│ │ └── WebView2.cs
│ └── macOS
│ └── Controls
│ └── WebView2.cs
├── CefGlue.Avalonia
├── CefGlue.Avalonia.csproj
└── README.md
├── Directory.Build.props
├── Directory.Packages.props
├── GeneratePackage.props
├── Microsoft.Maui.WebView
├── Core
│ ├── Core
│ │ ├── IElement.cs
│ │ ├── ITransform.cs
│ │ ├── IView.cs
│ │ └── IWebView.cs
│ ├── Graphics
│ │ ├── Color.cs
│ │ ├── Colors.cs
│ │ ├── IShadow.cs
│ │ ├── IShape.cs
│ │ └── Paint.cs
│ ├── Handlers
│ │ └── IElementHandler.cs
│ ├── IMauiContext.cs
│ └── Primitives
│ │ ├── FlowDirection.cs
│ │ ├── LayoutAlignment.cs
│ │ ├── SemanticHeadingLevel.cs
│ │ └── Semantics.cs
├── Microsoft.Maui.WebView.projitems
├── Microsoft.Maui.WebView.shproj
└── README.md
├── Version.props
└── WebView2.NativeAssets.Win32
├── README.md
├── WebView2.NativeAssets.Win32.bat
└── WebView2.NativeAssets.Win32.nuspec
/.github/ISSUE_TEMPLATE/bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "Bug Report \U0001F41B"
3 | about: 创建 Bug 报告以帮助我们改进 / Create a report to help us improve
4 | title: "\U0001F41B[BUG] 请输入标题(Please enter a title)"
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 |
18 |
19 | ### 🐛 描述(Description)
20 |
24 |
25 |
26 | ### 📷 复现步骤(Steps to Reproduce)
27 |
28 |
34 | 1.
35 | 2.
36 | 3.
37 |
38 | ### 📄 日志信息(Log Information)
39 |
47 |
48 | ### 🚑 基本信息(Basic Information)
49 |
50 | - 库版本(Library Version):
51 | - 系统版本号(OS Version):
52 |
53 | ### 🖼 截图(Screenshots)
54 |
55 |
59 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/question.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "Question \U0001F9D0"
3 | about: 对库使用的疑问或需要帮助 / Questions about the use of the library or need help
4 | title: "\U0001F9D0[Question] 请输入标题(Please enter a title)"
5 | labels: question
6 | assignees: ''
7 |
8 | ---
9 |
10 |
16 |
17 | ### 🧐 问题描述(Description)
18 |
19 |
23 |
24 | ### 🚑 其他信息(Other Information)
25 |
26 |
30 |
31 | - 库版本(Library Version):
32 | - 系统版本号(OS Version):
33 |
--------------------------------------------------------------------------------
/.github/workflows/CI.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | push:
4 | branches:
5 | - main
6 | tags:
7 | - "*"
8 | pull_request:
9 | workflow_dispatch:
10 |
11 | jobs:
12 | test:
13 | name: Test
14 | runs-on: ${{ matrix.os }}
15 | strategy:
16 | matrix:
17 | os: [ windows-latest ]
18 |
19 | steps:
20 | - name: Checkout repository
21 | uses: actions/checkout@v3
22 | with:
23 | fetch-depth: 0
24 | submodules: recursive
25 |
26 | - name: Setup .NET
27 | uses: actions/setup-dotnet@v2
28 | with:
29 | dotnet-version: 7.0.x
30 |
31 | - name: Verify dotnet info
32 | run: dotnet --info
33 |
34 | - name: Test
35 | shell: pwsh
36 | run: dotnet test -c Release
37 |
38 | build:
39 | name: Build
40 | needs: [ test ]
41 | if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}
42 | runs-on: windows-latest
43 | strategy:
44 | matrix:
45 | include:
46 | - ProjectName: "Avalonia.WebView2"
47 | PackageId: "WebView2.Avalonia"
48 |
49 | steps:
50 | - name: Checkout repository
51 | uses: actions/checkout@v3
52 | with:
53 | fetch-depth: 0
54 | submodules: recursive
55 |
56 | - name: Setup .NET
57 | uses: actions/setup-dotnet@v2
58 | with:
59 | dotnet-version: 7.0.x
60 |
61 | - name: Verify dotnet info
62 | run: dotnet --info
63 |
64 | - name: Build
65 | shell: pwsh
66 | run: dotnet build -c Release src\${{ matrix.ProjectName }}\${{ matrix.ProjectName }}.csproj
67 |
68 | - name: Run NativeAssets Bat
69 | shell: pwsh
70 | run: cmd.exe /c src\WebView2.NativeAssets.Win32.bat
71 |
72 | - name: Push nuget packages
73 | shell: pwsh
74 | run: |
75 | dotnet nuget push pkg\${{ matrix.PackageId }}*.nupkg -s https://nuget.pkg.github.com/BeyondDimension -k ${{ secrets.RMBADMIN_TOKEN }} --skip-duplicate
76 | dotnet nuget push pkg\${{ matrix.PackageId }}*.snupkg -s https://nuget.pkg.github.com/BeyondDimension -k ${{ secrets.RMBADMIN_TOKEN }} --skip-duplicate
77 | dotnet nuget push pkg\${{ matrix.PackageId }}*.nupkg -s https://api.nuget.org/v3/index.json -k ${{ secrets.NUGET_API_KEY }} --skip-duplicate
78 | dotnet nuget push pkg\${{ matrix.PackageId }}*.snupkg -s https://api.nuget.org/v3/index.json -k ${{ secrets.NUGET_API_KEY }} --skip-duplicate
79 | release:
80 | name: Release
81 | needs: build
82 | runs-on: ubuntu-latest
83 |
84 | steps:
85 | - name: Changelog
86 | uses: glennawatson/ChangeLog@v1
87 | id: changelog
88 |
89 | - name: Create Release
90 | uses: ncipollo/release-action@v1
91 | with:
92 | token: ${{ secrets.RMBADMIN_TOKEN }}
93 | body: ${{ steps.changelog.outputs.commitLog }}
94 | draft: false
95 | prerelease: false
96 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "ref/CefGlue"]
2 | path = ref/CefGlue
3 | url = https://github.com/BeyondDimension/CefGlue
4 |
--------------------------------------------------------------------------------
/Avalonia.WebView2.slnx:
--------------------------------------------------------------------------------
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 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Beyond Dimension
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Avalonia.WebView2 [](https://www.nuget.org/packages/WebView2.Avalonia/)
2 | Build .NET Avalonia Microsoft Edge WebView2 HTML5 Desktop Hybrid Apps
3 |
4 | ## Supported OS versions
5 | - [x] Windows (Edge WebView2)
6 | - [x] macOS (~~WebKit.WebView~~ | WebKit.WKWebView)
7 | - [ ] ~~Linux (CefGlue)~~
8 | - [ ] ~~Android (Xamarin.AndroidX.WebKit)~~
9 | - [ ] iOS (WebKit.WKWebView)
10 |
11 | ## [简介](https://docs.microsoft.com/zh-cn/microsoft-edge/webview2)
12 | Microsoft Edge WebView2 控件允许在本机应用中嵌入 web 技术(HTML、CSS 以及 JavaScript)。 WebView2 控件使用 [Microsoft Edge](https://www.microsoftedgeinsider.com) 作为绘制引擎,以在本机应用中显示 web 内容。
13 |
14 | 使用 WebView2 可以在本机应用的不同部分嵌入 Web 代码,或在单个 WebView2 实例中生成所有本机应用。
15 |
16 | 
17 |
18 | ## Screenshots
19 | 
20 | 
--------------------------------------------------------------------------------
/ref/CefGlue.Avalonia.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CefGlue.Common.Shared
6 | bin\**;obj\**
7 |
8 |
9 |
10 |
11 | CefGlue.Common
12 | bin\**;obj\**
13 |
14 |
15 |
16 |
17 | CefGlue.Avalonia
18 | bin\**;obj\**
19 |
20 |
21 |
22 |
23 | CefGlue
24 | bin\**;obj\**
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/ref/Microsoft.Web.WebView2/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (C) Microsoft Corporation. All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are
5 | met:
6 |
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above
10 | copyright notice, this list of conditions and the following disclaimer
11 | in the documentation and/or other materials provided with the
12 | distribution.
13 | * The name of Microsoft Corporation, or the names of its contributors
14 | may not be used to endorse or promote products derived from this
15 | software without specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/ref/Microsoft.Web.WebView2/NOTICE.txt:
--------------------------------------------------------------------------------
1 | NOTICES AND INFORMATION
2 | Do Not Translate or Localize
3 |
4 | This software incorporates material from third parties. Microsoft makes certain
5 | open source code available at https://3rdpartysource.microsoft.com, or you may
6 | send a check or money order for US $5.00, including the product name, the open
7 | source component name, and version number, to:
8 |
9 | Source Code Compliance Team
10 | Microsoft Corporation
11 | One Microsoft Way
12 | Redmond, WA 98052
13 | USA
14 |
15 | Notwithstanding any other terms, you may reverse engineer this software to the
16 | extent required to debug changes to any libraries licensed under the GNU Lesser
17 | General Public License.
18 |
19 | ----------------------------------------------------------------
20 |
21 | Antlr3.Runtime 3.5.2-rc1 - BSD 3-Clause
22 |
23 | [The "BSD license"]
24 | Copyright (c) 2011 The ANTLR Project
25 | All rights reserved.
26 |
27 | Redistribution and use in source and binary forms, with or without
28 | modification, are permitted provided that the following conditions
29 | are met:
30 |
31 | 1. Redistributions of source code must retain the above copyright
32 | notice, this list of conditions and the following disclaimer.
33 | 2. Redistributions in binary form must reproduce the above copyright
34 | notice, this list of conditions and the following disclaimer in the
35 | documentation and/or other materials provided with the distribution.
36 | 3. Neither the name of the copyright holder nor the names of its
37 | contributors may be used to endorse or promote products derived from
38 | this software without specific prior written permission.
39 |
40 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
41 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
42 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
43 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
44 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
46 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
47 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
48 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
49 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50 |
51 | ---------------------------------------------------------
52 |
53 | ---------------------------------------------------------
54 |
55 | StringTemplate4 4.0.9-rc1 - BSD 3-Clause
56 |
57 | [The "BSD license"]
58 | Copyright (c) 2011 The ANTLR Project
59 | All rights reserved.
60 |
61 | Redistribution and use in source and binary forms, with or without
62 | modification, are permitted provided that the following conditions
63 | are met:
64 |
65 | 1. Redistributions of source code must retain the above copyright
66 | notice, this list of conditions and the following disclaimer.
67 | 2. Redistributions in binary form must reproduce the above copyright
68 | notice, this list of conditions and the following disclaimer in the
69 | documentation and/or other materials provided with the distribution.
70 | 3. Neither the name of the copyright holder nor the names of its
71 | contributors may be used to endorse or promote products derived from
72 | this software without specific prior written permission.
73 |
74 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
75 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
76 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
77 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
78 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
79 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
80 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
81 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
82 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
83 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
84 |
85 | ---------------------------------------------------------
86 |
--------------------------------------------------------------------------------
/ref/Microsoft.Web.WebView2/lib/net462/Microsoft.Web.WebView2.Core.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BeyondDimension/Avalonia.WebView2/88baa44aab31213598b821794a4e06e97d2dde5e/ref/Microsoft.Web.WebView2/lib/net462/Microsoft.Web.WebView2.Core.dll
--------------------------------------------------------------------------------
/ref/Microsoft.Web.WebView2/lib/netcoreapp3.0/Microsoft.Web.WebView2.Core.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BeyondDimension/Avalonia.WebView2/88baa44aab31213598b821794a4e06e97d2dde5e/ref/Microsoft.Web.WebView2/lib/netcoreapp3.0/Microsoft.Web.WebView2.Core.dll
--------------------------------------------------------------------------------
/ref/Microsoft.Web.WebView2/runtimes/win-arm64/native/WebView2Loader.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BeyondDimension/Avalonia.WebView2/88baa44aab31213598b821794a4e06e97d2dde5e/ref/Microsoft.Web.WebView2/runtimes/win-arm64/native/WebView2Loader.dll
--------------------------------------------------------------------------------
/ref/Microsoft.Web.WebView2/runtimes/win-x64/native/WebView2Loader.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BeyondDimension/Avalonia.WebView2/88baa44aab31213598b821794a4e06e97d2dde5e/ref/Microsoft.Web.WebView2/runtimes/win-x64/native/WebView2Loader.dll
--------------------------------------------------------------------------------
/ref/Microsoft.Web.WebView2/runtimes/win-x86/native/WebView2Loader.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BeyondDimension/Avalonia.WebView2/88baa44aab31213598b821794a4e06e97d2dde5e/ref/Microsoft.Web.WebView2/runtimes/win-x86/native/WebView2Loader.dll
--------------------------------------------------------------------------------
/res/screenshots/Avalonia.WebView2.Sample.Win11.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BeyondDimension/Avalonia.WebView2/88baa44aab31213598b821794a4e06e97d2dde5e/res/screenshots/Avalonia.WebView2.Sample.Win11.webp
--------------------------------------------------------------------------------
/res/screenshots/Avalonia.WebView2.Sample.Win7.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BeyondDimension/Avalonia.WebView2/88baa44aab31213598b821794a4e06e97d2dde5e/res/screenshots/Avalonia.WebView2.Sample.Win7.webp
--------------------------------------------------------------------------------
/src/Avalonia.Ref/AssemblyInfo.Version.Max.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | [assembly: AssemblyVersion("255.255.255.255")]
--------------------------------------------------------------------------------
/src/Avalonia.Ref/Avalonia.Desktop/AppBuilderDesktopExtensions.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Platform;
3 |
4 | // https://github.com/AvaloniaUI/Avalonia/blob/0.10.13/src/Avalonia.Desktop/AppBuilderDesktopExtensions.cs
5 |
6 | namespace Avalonia
7 | {
8 | public static class AppBuilderDesktopExtensions
9 | {
10 | public static AppBuilder UsePlatformDetect(this AppBuilder builder)
11 | {
12 | #if WINDOWS || NETFRAMEWORK
13 | builder.UseWin32();
14 | #else
15 |
16 | // We don't have the ability to load every assembly right now, so we are
17 | // stuck with manual configuration here
18 | // Helpers are extracted to separate methods to take the advantage of the fact
19 | // that CLR doesn't try to load dependencies before referencing method is jitted
20 | // Additionally, by having a hard reference to each assembly,
21 | // we verify that the assemblies are in the final .deps.json file
22 | // so .NET Core knows where to load the assemblies from,.
23 |
24 | if (OperatingSystem.IsWindows())
25 | {
26 | builder.UseWin32();
27 | }
28 | else if (OperatingSystem.IsMacOS())
29 | {
30 | builder.UseAvaloniaNative();
31 | }
32 | else
33 | {
34 | builder.UseX11();
35 | }
36 | #endif
37 | builder.UseSkia();
38 | return builder;
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/src/Avalonia.Ref/Avalonia.Desktop/Avalonia.Desktop.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net462;net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows;net9.0;net9.0-windows
5 | true
6 | false
7 | ..\avalonia.snk
8 |
9 | true
10 | false
11 |
12 |
13 |
14 |
15 | Properties
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/Avalonia.Ref/Avalonia.Native/Avalonia.Native.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net462;netstandard2.0;
5 | true
6 | false
7 | ..\avalonia.snk
8 |
9 | true
10 | false
11 |
12 |
13 |
14 |
15 | Properties
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/Avalonia.Ref/Avalonia.Native/AvaloniaNativePlatformExtensions.cs:
--------------------------------------------------------------------------------
1 | #if !WINDOWS
2 |
3 | using System;
4 | using Avalonia.Controls;
5 |
6 | namespace Avalonia
7 | {
8 | public static class AvaloniaNativePlatformExtensions
9 | {
10 | public static AppBuilder UseAvaloniaNative(this AppBuilder builder)
11 | {
12 | throw new PlatformNotSupportedException();
13 | }
14 | }
15 | }
16 |
17 | #endif
--------------------------------------------------------------------------------
/src/Avalonia.Ref/Avalonia.X11/Avalonia.X11.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net462;netstandard2.0;
5 | true
6 | false
7 | ..\avalonia.snk
8 |
9 | true
10 | false
11 |
12 |
13 |
14 |
15 | Properties
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/Avalonia.Ref/Avalonia.X11/AvaloniaX11PlatformExtensions.cs:
--------------------------------------------------------------------------------
1 | #if !WINDOWS
2 |
3 | using System;
4 | using Avalonia.Controls;
5 |
6 | namespace Avalonia
7 | {
8 | public static class AvaloniaX11PlatformExtensions
9 | {
10 | public static AppBuilder UseX11(this AppBuilder builder)
11 | {
12 | throw new PlatformNotSupportedException();
13 | }
14 | }
15 | }
16 |
17 | #endif
18 |
--------------------------------------------------------------------------------
/src/Avalonia.Ref/avalonia.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BeyondDimension/Avalonia.WebView2/88baa44aab31213598b821794a4e06e97d2dde5e/src/Avalonia.Ref/avalonia.snk
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile.Android/Avalonia.WebView2.Sample.Mobile.Android.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net9.0-android
6 | com.github.beyonddimension.avalonia.webview2.sample
7 | 1
8 | 1.0
9 | apk
10 | false
11 | Avalonia.WebView2.Sample
12 |
13 |
14 |
15 |
16 | Resources\drawable\Icon.png
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile.Android/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BeyondDimension/Avalonia.WebView2/88baa44aab31213598b821794a4e06e97d2dde5e/src/Avalonia.WebView2.Sample.Mobile.Android/Icon.png
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile.Android/MainActivity.cs:
--------------------------------------------------------------------------------
1 | using Android.App;
2 | using Android.Content.PM;
3 | using Avalonia;
4 | using Avalonia.Android;
5 | using Avalonia.ReactiveUI;
6 |
7 | namespace Avalonia.WebView2.Sample;
8 |
9 | [Activity(
10 | Label = "Avalonia.WebView2.Sample",
11 | Theme = "@style/MyTheme.NoActionBar",
12 | Icon = "@drawable/icon",
13 | MainLauncher = true,
14 | ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
15 | public class MainActivity : AvaloniaMainActivity
16 | {
17 | protected override AppBuilder CustomizeAppBuilder(AppBuilder builder)
18 | {
19 | return base.CustomizeAppBuilder(builder)
20 | .WithInterFont()
21 | .UseReactiveUI();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile.Android/Properties/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile.Android/Resources/AboutResources.txt:
--------------------------------------------------------------------------------
1 | Images, layout descriptions, binary blobs and string dictionaries can be included
2 | in your application as resource files. Various Android APIs are designed to
3 | operate on the resource IDs instead of dealing with images, strings or binary blobs
4 | directly.
5 |
6 | For example, a sample Android app that contains a user interface layout (main.axml),
7 | an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
8 | would keep its resources in the "Resources" directory of the application:
9 |
10 | Resources/
11 | drawable/
12 | icon.png
13 |
14 | layout/
15 | main.axml
16 |
17 | values/
18 | strings.xml
19 |
20 | In order to get the build system to recognize Android resources, set the build action to
21 | "AndroidResource". The native Android APIs do not operate directly with filenames, but
22 | instead operate on resource IDs. When you compile an Android application that uses resources,
23 | the build system will package the resources for distribution and generate a class called "R"
24 | (this is an Android convention) that contains the tokens for each one of the resources
25 | included. For example, for the above Resources layout, this is what the R class would expose:
26 |
27 | public class R {
28 | public class drawable {
29 | public const int icon = 0x123;
30 | }
31 |
32 | public class layout {
33 | public const int main = 0x456;
34 | }
35 |
36 | public class strings {
37 | public const int first_string = 0xabc;
38 | public const int second_string = 0xbcd;
39 | }
40 | }
41 |
42 | You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
43 | to reference the layout/main.axml file, or R.strings.first_string to reference the first
44 | string in the dictionary file values/strings.xml.
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile.Android/Resources/drawable-night-v31/avalonia_anim.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
11 |
15 |
16 |
20 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
42 |
43 |
44 |
45 |
46 |
53 |
54 |
55 |
56 |
57 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile.Android/Resources/drawable-v31/avalonia_anim.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
11 |
15 |
16 |
21 |
27 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
46 |
47 |
48 |
49 |
50 |
57 |
58 |
59 |
60 |
61 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile.Android/Resources/drawable/splash_screen.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 |
8 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile.Android/Resources/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #212121
4 |
5 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile.Android/Resources/values-v31/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
17 |
21 |
22 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile.Android/Resources/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
5 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile.Android/Resources/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile.iOS/AppDelegate.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.iOS;
4 | using Avalonia.Media;
5 | using Avalonia.ReactiveUI;
6 | using Foundation;
7 | using UIKit;
8 |
9 | namespace Avalonia.WebView2.Sample;
10 |
11 | // The UIApplicationDelegate for the application. This class is responsible for launching the
12 | // User Interface of the application, as well as listening (and optionally responding) to
13 | // application events from iOS.
14 | [Register("AppDelegate")]
15 | #pragma warning disable CA1711 // Identifiers should not have incorrect suffix
16 | public partial class AppDelegate : AvaloniaAppDelegate
17 | #pragma warning restore CA1711 // Identifiers should not have incorrect suffix
18 | {
19 | protected override AppBuilder CustomizeAppBuilder(AppBuilder builder)
20 | {
21 | return base.CustomizeAppBuilder(builder)
22 | .WithInterFont()
23 | .UseReactiveUI();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile.iOS/Avalonia.WebView2.Sample.Mobile.iOS.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net9.0-ios
6 | Avalonia.WebView2.Sample
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile.iOS/Entitlements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile.iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDisplayName
6 | Avalonia.WebView2.Sample
7 | CFBundleIdentifier
8 | com.github.beyonddimension.avalonia.webview2.sample
9 | CFBundleShortVersionString
10 | 1.0
11 | CFBundleVersion
12 | 1.0
13 | LSRequiresIPhoneOS
14 |
15 | MinimumOSVersion
16 | 13.0
17 | UIDeviceFamily
18 |
19 | 1
20 | 2
21 |
22 | UILaunchStoryboardName
23 | LaunchScreen
24 | UIRequiredDeviceCapabilities
25 |
26 | armv7
27 |
28 | UISupportedInterfaceOrientations
29 |
30 | UIInterfaceOrientationPortrait
31 | UIInterfaceOrientationPortraitUpsideDown
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile.iOS/Main.cs:
--------------------------------------------------------------------------------
1 | using UIKit;
2 |
3 | namespace Avalonia.WebView2.Sample;
4 | static class Application
5 | {
6 | // This is the main entry point of the application.
7 | static void Main(string[] args)
8 | {
9 | // if you want to use a different Application Delegate class from "AppDelegate"
10 | // you can specify it here.
11 | UIApplication.Main(args, null, typeof(AppDelegate));
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile.iOS/Resources/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
21 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile/App.axaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile/App.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls.ApplicationLifetimes;
3 | using Avalonia.Markup.Xaml;
4 | using Avalonia.WebView2.Sample.ViewModels;
5 | using Avalonia.WebView2.Sample.Views;
6 |
7 | namespace Avalonia.WebView2.Sample;
8 |
9 | public partial class App : Application
10 | {
11 | public override void Initialize()
12 | {
13 | AvaloniaXamlLoader.Load(this);
14 | }
15 |
16 | public override void OnFrameworkInitializationCompleted()
17 | {
18 | //if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
19 | //{
20 | // desktop.MainWindow = new MainWindow
21 | // {
22 | // DataContext = new MainViewModel()
23 | // };
24 | //}
25 | //else
26 | // 此示例项目仅移动端
27 | if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)
28 | {
29 | singleViewPlatform.MainView = new MainView
30 | {
31 | DataContext = new MainViewModel()
32 | };
33 | }
34 |
35 | base.OnFrameworkInitializationCompleted();
36 | }
37 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile/Assets/avalonia-logo.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BeyondDimension/Avalonia.WebView2/88baa44aab31213598b821794a4e06e97d2dde5e/src/Avalonia.WebView2.Sample.Mobile/Assets/avalonia-logo.ico
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile/Avalonia.WebView2.Sample.Mobile.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | Avalonia.WebView2.Sample
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile/ViewLocator.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 | using Avalonia.Controls.Templates;
3 | using Avalonia.WebView2.Sample.ViewModels;
4 |
5 | namespace Avalonia.WebView2.Sample;
6 |
7 | public class ViewLocator : IDataTemplate
8 | {
9 | public Control? Build(object? data)
10 | {
11 | if (data is null)
12 | return null;
13 |
14 | var name = data.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
15 | var type = Type.GetType(name);
16 |
17 | if (type != null)
18 | {
19 | return (Control)Activator.CreateInstance(type)!;
20 | }
21 |
22 | return new TextBlock { Text = "Not Found: " + name };
23 | }
24 |
25 | public bool Match(object? data)
26 | {
27 | return data is ViewModelBase;
28 | }
29 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile/ViewModels/MainViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace Avalonia.WebView2.Sample.ViewModels;
2 |
3 | public partial class MainViewModel : ViewModelBase
4 | {
5 | #pragma warning disable CA1822 // Mark members as static
6 | public string Source => "https://bing.com";
7 | #pragma warning restore CA1822 // Mark members as static
8 | }
9 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile/ViewModels/ViewModelBase.cs:
--------------------------------------------------------------------------------
1 | using ReactiveUI;
2 |
3 | namespace Avalonia.WebView2.Sample.ViewModels;
4 |
5 | public abstract class ViewModelBase : ReactiveObject
6 | {
7 | }
8 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile/Views/MainView.axaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile/Views/MainView.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 |
3 | namespace Avalonia.WebView2.Sample.Views;
4 |
5 | public partial class MainView : UserControl
6 | {
7 | public MainView()
8 | {
9 | InitializeComponent();
10 | }
11 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile/Views/MainWindow.axaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample.Mobile/Views/MainWindow.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 |
3 | namespace Avalonia.WebView2.Sample.Views;
4 |
5 | public partial class MainWindow : Window
6 | {
7 | public MainWindow()
8 | {
9 | InitializeComponent();
10 | }
11 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls.ApplicationLifetimes;
2 | using Avalonia.Markup.Xaml;
3 |
4 | namespace Avalonia.WebView2.Sample;
5 |
6 | public sealed class App : Application
7 | {
8 | public override void Initialize()
9 | {
10 | AvaloniaXamlLoader.Load(this);
11 | InitWebView2();
12 | }
13 |
14 | public override void OnFrameworkInitializationCompleted()
15 | {
16 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
17 | {
18 | desktop.MainWindow = new MainWindow();
19 | }
20 |
21 | base.OnFrameworkInitializationCompleted();
22 | }
23 |
24 | static void InitWebView2()
25 | {
26 | #if WINDOWS
27 | if (global::Avalonia.Controls.WebView2.IsSupported)
28 | {
29 | //AvaloniaWebView2.DefaultCreationProperties = new()
30 | //{
31 | // Language = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
32 | // UserDataFolder = GetUserDataFolder(),
33 | //};
34 |
35 | //static string GetUserDataFolder()
36 | //{
37 | // var path = Path.Combine(AppContext.BaseDirectory, "AppData", "WebView2", "UserData");
38 | // if (!Directory.Exists(path)) Directory.CreateDirectory(path);
39 | // return path;
40 | //}
41 | }
42 | #elif !(WINDOWS || NETFRAMEWORK) && NET8_0_OR_GREATER
43 | #endif
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample/Avalonia.WebView2.Sample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | true
5 |
6 |
7 |
8 |
9 |
10 |
11 | net9.0-windows;net9.0
12 |
13 |
14 |
15 |
16 |
17 | net9.0-macos
18 |
19 |
20 |
21 |
22 |
23 | net9.0
24 |
25 |
26 |
27 |
28 |
29 |
30 | LINUX;$(DefineConstants)
31 |
32 |
33 |
34 |
35 |
36 | WinExe
37 | Properties\app.manifest
38 | net9.0-windows;net9.0
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | Exe
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
71 | .allowedextension
72 |
73 | none
74 | false
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample/BCL/MS/Internal/PresentationCore/SR.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 | // https://github.com/dotnet/wpf/blob/v6.0.6/src/Microsoft.DotNet.Wpf/src/PresentationCore/SR.cs
5 |
6 | #if !NETFRAMEWORK && WINDOWS
7 |
8 | namespace MS.Internal.PresentationCore;
9 |
10 | internal static class SR
11 | {
12 | public static string Get(string name) => name switch
13 | {
14 | SRID.CantShowMBServiceWithOwner => "Cannot show MessageBox Service with Owner.",
15 | _ => "",
16 | };
17 | }
18 |
19 | #endif
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample/BCL/MS/Internal/PresentationCore/SRID.cs:
--------------------------------------------------------------------------------
1 | #if !NETFRAMEWORK && WINDOWS
2 |
3 | namespace MS.Internal.PresentationCore;
4 |
5 | static class SRID
6 | {
7 | ///
8 | /// https://github.com/dotnet/wpf/blob/v6.0.6/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Resources/Strings.resx#L510
9 | ///
10 | public const string CantShowMBServiceWithOwner = "CantShowMBServiceWithOwner";
11 | }
12 |
13 | #endif
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample/BCL/MS/Win32/ExternDll.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 | // https://github.com/dotnet/wpf/blob/v6.0.6/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/ExternDll.cs
5 |
6 | #if !NETFRAMEWORK && WINDOWS
7 |
8 | namespace MS.Win32;
9 |
10 | internal static class ExternDll
11 | {
12 | //public const string Activeds = "activeds.dll";
13 | //public const string Advapi32 = "advapi32.dll";
14 | //public const string Comctl32 = "comctl32.dll";
15 | //public const string Comdlg32 = "comdlg32.dll";
16 | //public const string DwmAPI = "dwmapi.dll";
17 | //public const string Gdi32 = "gdi32.dll";
18 | //public const string Gdiplus = "gdiplus.dll";
19 | //public const string Hhctrl = "hhctrl.ocx";
20 | //public const string Imm32 = "imm32.dll";
21 | //public const string Kernel32 = "kernel32.dll";
22 | //public const string Loadperf = "Loadperf.dll";
23 | //public const string Mqrt = "mqrt.dll";
24 | //public const string Mscoree = "mscoree.dll";
25 | //public const string MsDrm = "msdrm.dll";
26 | //public const string Mshwgst = "mshwgst.dll";
27 | //public const string Msi = "msi.dll";
28 | //public const string NaturalLanguage6 = "naturallanguage6.dll";
29 | //public const string Ntdll = "ntdll.dll";
30 | //public const string Ole32 = "ole32.dll";
31 | //public const string Oleacc = "oleacc.dll";
32 | //public const string Oleaut32 = "oleaut32.dll";
33 | //public const string Olepro32 = "olepro32.dll";
34 | //public const string Penimc = "PenIMC_cor3.dll";
35 | //public const string PresentationCore = "PresentationCore.dll";
36 | //public const string PresentationFramework = "PresentationFramework.dll";
37 | //public const string PresentationHostDll = "PresentationHost_cor3.dll";
38 | //public const string PresentationNativeDll = "PresentationNative_cor3.dll";
39 | //public const string Psapi = "psapi.dll";
40 | //public const string Shcore = "shcore.dll";
41 | //public const string Shell32 = "shell32.dll";
42 | //public const string Shfolder = "shfolder.dll";
43 | //public const string Urlmon = "urlmon.dll";
44 | public const string User32 = "user32.dll";
45 | //public const string Uxtheme = "uxtheme.dll";
46 | //public const string Version = "version.dll";
47 | //public const string Vsassert = "vsassert.dll";
48 | //public const string WindowsBase = "windowsbase.dll";
49 | //public const string Wininet = "wininet.dll";
50 | //public const string Winmm = "winmm.dll";
51 | //public const string Winspool = "winspool.drv";
52 | //public const string Wldp = "wldp.dll";
53 | //public const string WpfGfx = "WpfGfx_cor3.dll";
54 | //public const string WtsApi32 = "wtsapi32.dll";
55 | }
56 |
57 | #endif
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample/BCL/MS/Win32/UnsafeNativeMethodsCLR.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 | // https://github.com/dotnet/wpf/blob/v6.0.6/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/UnsafeNativeMethodsCLR.cs
5 |
6 | #if !NETFRAMEWORK && WINDOWS
7 |
8 | using System.Runtime.InteropServices;
9 |
10 | namespace MS.Win32;
11 |
12 | internal static class UnsafeNativeMethods
13 | {
14 | [DllImport(ExternDll.User32, ExactSpelling = true, CharSet = CharSet.Auto)]
15 | public static extern IntPtr GetActiveWindow();
16 |
17 | [DllImport(ExternDll.User32, SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)]
18 | public static extern int MessageBox(HandleRef hWnd, string text, string caption, int type);
19 | }
20 |
21 | #endif
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample/Common8/DomainPattern.cs:
--------------------------------------------------------------------------------
1 | // https://github.com/BeyondDimension/Common/blob/dev8/src/BD.Common8.Bcl/Net/DomainPattern.cs
2 |
3 | using System.Collections.Immutable;
4 | using System.Text.RegularExpressions;
5 |
6 | namespace System.Net;
7 |
8 | ///
9 | /// 域名表达式
10 | /// * 表示除 . 之外任意 0 到多个字符
11 | ///
12 | sealed class DomainPattern : IComparable
13 | {
14 | ///
15 | /// 通用分隔符
16 | ///
17 | public const char GeneralSeparator = ';';
18 |
19 | readonly ImmutableArray regexs;
20 | readonly string domainPattern;
21 |
22 | ///
23 | /// 排序
24 | ///
25 | public long Order { get; init; }
26 |
27 | ///
28 | /// Initializes a new instance of the class.
29 | ///
30 | ///
31 | public DomainPattern(string domainPattern)
32 | {
33 | if (string.IsNullOrWhiteSpace(domainPattern))
34 | throw new ArgumentNullException(nameof(domainPattern));
35 |
36 | this.domainPattern = domainPattern;
37 |
38 | var items = domainPattern.Split(
39 | #if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_0_OR_GREATER
40 | GeneralSeparator,
41 | #else
42 | [GeneralSeparator],
43 | #endif
44 | StringSplitOptions.RemoveEmptyEntries);
45 |
46 | regexs = items.Select(s =>
47 | {
48 | var isRegex = s.StartsWith(
49 | #if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_0_OR_GREATER
50 | '/'
51 | #else
52 | "/"
53 | #endif
54 | );
55 | if (isRegex)
56 | {
57 | return new Regex(s[1..], RegexOptions.IgnoreCase);
58 | }
59 | else
60 | {
61 | var regexPattern = Regex.Escape(s).Replace(@"\*", @"[^\.]*");
62 | return new Regex($"^{regexPattern}", RegexOptions.IgnoreCase);
63 | }
64 | #pragma warning disable IDE0305 // 简化集合初始化
65 | }).ToImmutableArray();
66 | #pragma warning restore IDE0305 // 简化集合初始化
67 | }
68 |
69 | ///
70 | /// 与目标比较
71 | ///
72 | ///
73 | ///
74 | public int CompareTo(DomainPattern? other)
75 | {
76 | if (other is null)
77 | {
78 | return 1;
79 | }
80 |
81 | if (Order < other.Order)
82 | {
83 | return -1;
84 | }
85 | else if (Order > other.Order)
86 | {
87 | return 1;
88 | }
89 |
90 | var segmentsX = domainPattern.Split('.');
91 | var segmentsY = other.domainPattern.Split('.');
92 | var value = segmentsX.Length - segmentsY.Length;
93 | if (value != 0)
94 | {
95 | return value;
96 | }
97 |
98 | for (var i = segmentsX.Length - 1; i >= 0; i--)
99 | {
100 | var x = segmentsX[i];
101 | var y = segmentsY[i];
102 |
103 | value = Compare(x, y);
104 | if (value == 0)
105 | {
106 | continue;
107 | }
108 | return value;
109 | }
110 |
111 | return 0;
112 | }
113 |
114 | ///
115 | /// 比较两个分段
116 | ///
117 | ///
118 | ///
119 | ///
120 | static int Compare(string x, string y)
121 | {
122 | var valueX = x.Replace('*', char.MaxValue);
123 | var valueY = y.Replace('*', char.MaxValue);
124 | return valueX.CompareTo(valueY);
125 | }
126 |
127 | ///
128 | /// 是否与指定字符串匹配
129 | ///
130 | ///
131 | ///
132 | public bool IsMatch(string value) => regexs.Any(s => s.IsMatch(value));
133 |
134 | ///
135 | /// 是否与指定域名匹配
136 | ///
137 | ///
138 | ///
139 | public bool IsMatchOnlyDomain(string domain)
140 | {
141 | try
142 | {
143 | if (domain.Contains('/'))
144 | {
145 | Uri uri = new(domain);
146 | domain = uri.Host;
147 | }
148 | }
149 | catch
150 | {
151 | }
152 | var result = regexs.Any(s => s.IsMatch(domain));
153 | return result;
154 | }
155 |
156 | ///
157 | public override string ToString() => domainPattern;
158 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
23 |
27 |
28 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Win32;
2 | using System.Windows;
3 |
4 | #if !(WINDOWS || NETFRAMEWORK) && NET8_0_OR_GREATER && !ANDROID && !IOS
5 | using Xilium.CefGlue;
6 | using Xilium.CefGlue.Common;
7 | #endif
8 |
9 |
10 | namespace Avalonia.WebView2.Sample;
11 |
12 | static class Program
13 | {
14 | // Initialization code. Don't use any Avalonia, third-party APIs or any
15 | // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
16 | // yet and stuff might break.
17 | [STAThread]
18 | public static void Main(string[] args)
19 | {
20 | #if WINDOWS
21 | // If urn:schemas-microsoft-com:compatibility.v1 supportedOS exists in the app.manifest file, the control will not display normally, but it is normal in WPF
22 | if (IsProgramInCompatibilityMode())
23 | {
24 | // It's strange that the control running in compatibility mode can't display normally, but it works in WPF
25 | MessageBox.Show("Windows Program Compatibility mode is on. Turn it off and then try again", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
26 | return;
27 | }
28 | #endif
29 |
30 | BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
31 | }
32 |
33 | #if WINDOWS
34 | static bool IsProgramInCompatibilityMode()
35 | {
36 | try
37 | {
38 | foreach (var item in new[] { Registry.CurrentUser, Registry.LocalMachine })
39 | {
40 | using var layers = item.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers");
41 | var value = layers?.GetValue(Environment.ProcessPath)?.ToString();
42 | if (value != null)
43 | {
44 | if (value.Contains("WIN8RTM", StringComparison.OrdinalIgnoreCase)) return true;
45 | if (value.Contains("WIN7RTM", StringComparison.OrdinalIgnoreCase)) return true;
46 | }
47 | }
48 | }
49 | catch
50 | {
51 | }
52 | return false;
53 | }
54 | #endif
55 |
56 | // Avalonia configuration, don't remove; also used by visual designer.
57 | public static AppBuilder BuildAvaloniaApp()
58 | {
59 | var b = AppBuilder.Configure()
60 | .UsePlatformDetect()
61 | .LogToTrace()
62 | #if !(WINDOWS || NETFRAMEWORK) && NET8_0_OR_GREATER && !ANDROID && !IOS
63 | .With(new X11PlatformOptions())
64 | //.AfterSetup(_ => CefRuntimeLoader.Initialize(new CefSettings()
65 | //{
66 | // RootCachePath = GetCachePath(),
67 | // WindowlessRenderingEnabled = false,
68 | // LogSeverity = CefLogSeverity.Verbose,
69 | //}))
70 | #endif
71 | ;
72 | return b;
73 | }
74 |
75 | #if !(WINDOWS || NETFRAMEWORK) && NET8_0_OR_GREATER && !ANDROID && !IOS
76 | static string GetCachePath() => Path.Combine(Path.GetTempPath(), "CefGlue_" + Guid.NewGuid().ToString().Replace("-", null));
77 | #endif
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample/Properties/PublishProfiles/win-x64.pubxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Release
5 | Any CPU
6 | bin\Release\Publish
7 | FileSystem
8 | net7.0-windows
9 | win7-x64
10 | true
11 | true
12 | false
13 | false
14 | true
15 |
16 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample/Properties/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | true/PM
7 | PerMonitorV2, PerMonitor
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample/WebView2Compat.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2.Sample/WebView2Compat.xaml.cs:
--------------------------------------------------------------------------------
1 | #if WINDOWS
2 | using Microsoft.Web.WebView2.Core;
3 | #endif
4 | using Avalonia.Controls;
5 | using Avalonia.Markup.Xaml;
6 | using System.Net;
7 | using Avalonia.Media;
8 | using IStorageService = Avalonia.Controls.WebView2.IStorageService;
9 | using static Avalonia.Controls.WebView2;
10 |
11 | namespace Avalonia.WebView2.Sample;
12 |
13 | public sealed partial class WebView2Compat : UserControl, IStorageService
14 | {
15 | public WebView2Compat()
16 | {
17 | InitializeComponent();
18 | WebView2 = this.FindControl("WebView2")!;
19 | WebView2.IsVisible = false;
20 | TextBlock = this.FindControl("TextBlock")!;
21 | #if WINDOWS
22 | // 设置背景色透明
23 | WebView2.Fill = new SolidColorBrush(Colors.Transparent);
24 | if (!IsSupported)
25 | {
26 | TextBlock.Text = "Couldn't find a compatible Webview2 Runtime installation to host WebViews.";
27 | }
28 | else
29 | {
30 | WebView2.DOMContentLoaded += WebView2_DOMContentLoaded;
31 | //WebView2.DocumentCreatedLoader = new Controls.WebView2.WebView2OnDocumentCreatedLoader
32 | //{
33 | // LocalStorage = (options) => { },
34 | // SessionStorage = (options) => { },
35 | //};
36 | }
37 | WebView2.StorageService = this;
38 | #endif
39 | }
40 |
41 | #if WINDOWS
42 | void WebView2_DOMContentLoaded(object? sender, CoreWebView2DOMContentLoadedEventArgs e)
43 | {
44 | WebView2.IsVisible = true;
45 | }
46 | #endif
47 |
48 | private void InitializeComponent()
49 | {
50 | AvaloniaXamlLoader.Load(this);
51 | }
52 |
53 | readonly DomainPattern bingComDomainPattern = new("*bing.com");
54 |
55 | IEnumerable>? IStorageService.GetStorages(string requestUri)
56 | {
57 | // 测试 localStorage 注入
58 | var now = DateTime.Now;
59 |
60 | var dict = new Dictionary<(StorageItemType type, string key), StorageItemValue>()
61 | {
62 | { (StorageItemType.LocalStorage, "global_test"), 2 },
63 | { (StorageItemType.SessionStorage, "global_test_s"), 7.5 },
64 | { (StorageItemType.LocalStorage, "global_test_now"), now },
65 | { (StorageItemType.AllStorage, "global_test_now_str"), now.ToString("yyyy-MM-dd HH:mm:ss.fffffff") },
66 | };
67 |
68 | foreach (var it in dict)
69 | {
70 | yield return it;
71 | }
72 |
73 | if (bingComDomainPattern.IsMatchOnlyDomain(requestUri))
74 | {
75 | var dict2 = new Dictionary<(StorageItemType type, string key), StorageItemValue>()
76 | {
77 | { (StorageItemType.LocalStorage, "bing.com"), 4.5f },
78 | { (StorageItemType.LocalStorage, "bing"), "key4" },
79 | { (StorageItemType.LocalStorage, "bing3"), now },
80 | { (StorageItemType.LocalStorage, "bing4"), now.ToString("yyyy-MM-dd HH:mm:ss.fffffff") },
81 | };
82 |
83 | foreach (var it in dict2)
84 | {
85 | yield return it;
86 | }
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Avalonia.WebView2.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | true
5 | true
6 | Avalonia
7 | WebView2.Avalonia
8 |
9 | The WebView2 control enables you to embed web technologies (HTML, CSS, and JavaScript) in your native applications powered by Microsoft Edge (Chromium).
10 | This package is necessary for Avalonia applications. To learn more about package versions checkout https://aka.ms/wv2-packageversion. To learn best practices checkout: https://aka.ms/wv2-bestpractices.
11 |
12 | Web WebView Native native package Edge avalonia avaloniaui dotnet framework core Webview2
13 | 1.0.3240.44-preview.250530.1
14 |
15 |
16 |
17 |
18 |
19 |
20 | net462;netstandard2.0;net6.0;net6.0-windows;net7.0;net7.0-windows;net8.0;net8.0-windows;net9.0;net9.0-windows
21 |
22 | $(TargetFrameworks);net9.0-android;net9.0-ios;net9.0-macos
23 |
24 |
25 |
26 |
27 |
28 |
29 | net9.0-macos
30 |
31 |
32 |
33 |
34 |
35 | net9.0
36 |
37 |
38 |
39 |
40 |
41 |
42 | LINUX;$(DefineConstants)
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 | all
76 | runtime; build; native; contentfiles; analyzers; buildtransitive
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Compat/IsExternalInit.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/IsExternalInit.cs
4 | // https://stackoverflow.com/questions/64749385/predefined-type-system-runtime-compilerservices-isexternalinit-is-not-defined
5 | // https://stackoverflow.com/questions/62648189/testing-c-sharp-9-0-in-vs2019-cs0518-isexternalinit-is-not-defined-or-imported
6 | // https://github.com/dotnet/roslyn/issues/45510
7 | // https://docs.microsoft.com/zh-cn/dotnet/api/system.runtime.compilerservices.isexternalinit?view=net-6.0
8 | #if !NETCOREAPP
9 | using System.ComponentModel;
10 |
11 | namespace System.Runtime.CompilerServices;
12 |
13 | ///
14 | /// 保留供编译器用于跟踪元数据。 开发人员不应在源代码中使用此类。
15 | ///
16 | [EditorBrowsable(EditorBrowsableState.Never)]
17 | class IsExternalInit
18 | {
19 | }
20 | #endif
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/StorageService/IStorageService.cs:
--------------------------------------------------------------------------------
1 | namespace Avalonia.Controls;
2 |
3 | partial class WebView2
4 | {
5 | ///
6 | /// Web Storage 提供了访问特定域名下的会话存储或本地存储的功能,例如,可以添加、修改或删除存储的数据项。
7 | /// 如果你想要操作一个域名的会话存储,可以使用 Window.sessionStorage;如果想要操作一个域名的本地存储,可以使用 Window.localStorage。
8 | ///
9 | public interface IStorageService
10 | {
11 | ///
12 | /// 根据请求地址获取存储数据
13 | ///
14 | ///
15 | IEnumerable>? GetStorages(
16 | string requestUri);
17 | }
18 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/StorageService/StorageItemOperate.cs:
--------------------------------------------------------------------------------
1 | namespace Avalonia.Controls;
2 |
3 | partial class WebView2
4 | {
5 | ///
6 | /// localStorage 或 sessionStorage 的操作类型
7 | ///
8 | public enum StorageItemOperate : byte
9 | {
10 | ///
11 | /// 设置键值项
12 | ///
13 | SetItem = 1,
14 |
15 | ///
16 | /// 移除键值项
17 | ///
18 | RemoveItem,
19 |
20 | ///
21 | /// 清空所有键值项
22 | ///
23 | ClearAll,
24 | }
25 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/StorageService/StorageItemType.cs:
--------------------------------------------------------------------------------
1 | namespace Avalonia.Controls;
2 |
3 | partial class WebView2
4 | {
5 | ///
6 | /// storageItem 类型是 localStorage 还是 sessionStorage
7 | ///
8 | public enum StorageItemType : byte
9 | {
10 | ///
11 | /// 只读的 localStorage 属性允许你访问一个 Document 源(origin)的对象 Storage;存储的数据将保存在浏览器会话中。localStorage 类似 sessionStorage,但其区别在于:存储在 localStorage 的数据可以长期保留;而当页面会话结束——也就是说,当页面被关闭时,存储在 sessionStorage 的数据会被清除。
12 | /// https://developer.mozilla.org/zh-CN/docs/Web/API/Window/localStorage
13 | ///
14 | LocalStorage = 1,
15 |
16 | ///
17 | /// sessionStorage 属性允许你访问一个,对应当前源的 session Storage 对象。它与 localStorage 相似,不同之处在于 localStorage 里面存储的数据没有过期时间设置,而存储在 sessionStorage 里面的数据在页面会话结束时会被清除。
18 | /// https://developer.mozilla.org/zh-CN/docs/Web/API/Window/sessionStorage
19 | ///
20 | SessionStorage,
21 |
22 | ///
23 | /// AND
24 | ///
25 | AllStorage,
26 | }
27 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/StorageService/StorageItemValue.JavaScriptStringEncode.cs:
--------------------------------------------------------------------------------
1 | using System.Buffers;
2 | using Utf8StringInterpolation;
3 |
4 | namespace Avalonia.Controls;
5 |
6 | partial class WebView2
7 | {
8 | partial class StorageItemValue
9 | {
10 | #if NET8_0_OR_GREATER
11 | static readonly SearchValues s_invalidJavaScriptChars = SearchValues.Create(
12 | // Any Control, < 32 (' ')
13 | "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F" +
14 | // Chars which must be encoded per JSON spec / HTML-sensitive chars encoded for safety
15 | "\"&'<>\\" +
16 | // newline chars (see Unicode 6.2, Table 5-1 [http://www.unicode.org/versions/Unicode6.2.0/ch05.pdf]) have to be encoded
17 | "\u0085\u2028\u2029");
18 |
19 | ///
20 | /// https://github.com/dotnet/runtime/blob/v10.0.0-preview.3.25171.5/src/libraries/System.Web.HttpUtility/src/System/Web/Util/HttpEncoder.cs#L129
21 | ///
22 | protected static void AppendJavaScriptStringEncode(ref Utf8StringWriter> writer, ReadOnlySpan value, bool addDoubleQuotes = false)
23 | {
24 | int i = value.IndexOfAny(s_invalidJavaScriptChars);
25 | if (i < 0)
26 | {
27 | if (addDoubleQuotes)
28 | {
29 | writer.AppendFormatted("\""u8);
30 | writer.AppendFormatted(value);
31 | writer.AppendFormatted("\""u8);
32 | }
33 | else
34 | {
35 | writer.AppendFormatted(value);
36 | }
37 | return;
38 | }
39 |
40 | // EncodeCore
41 |
42 | if (addDoubleQuotes)
43 | {
44 | writer.AppendFormatted("\""u8);
45 | }
46 |
47 | ReadOnlySpan chars = value;
48 | do
49 | {
50 | writer.AppendFormatted(chars[..i]);
51 | char c = chars[i];
52 | chars = chars[(i + 1)..];
53 | switch (c)
54 | {
55 | case '\r':
56 | writer.AppendFormatted("\\r"u8);
57 | break;
58 | case '\t':
59 | writer.AppendFormatted("\\t"u8);
60 | break;
61 | case '\"':
62 | writer.AppendFormatted("\\\""u8);
63 | break;
64 | case '\\':
65 | writer.AppendFormatted("\\\\"u8);
66 | break;
67 | case '\n':
68 | writer.AppendFormatted("\\n"u8);
69 | break;
70 | case '\b':
71 | writer.AppendFormatted("\\b"u8);
72 | break;
73 | case '\f':
74 | writer.AppendFormatted("\\f"u8);
75 | break;
76 | default:
77 | writer.AppendFormatted("\\u"u8);
78 | writer.AppendFormatted((int)c, 0, "x4");
79 | break;
80 | }
81 |
82 | i = chars.IndexOfAny(s_invalidJavaScriptChars);
83 | } while (i >= 0);
84 |
85 | writer.AppendFormatted(chars);
86 |
87 | if (addDoubleQuotes)
88 | {
89 | writer.AppendFormatted("\""u8);
90 | }
91 | }
92 | #else
93 | protected static void AppendJavaScriptStringEncode(ref Utf8StringWriter> writer, string? value)
94 | {
95 | if (value == null)
96 | {
97 | writer.AppendFormatted("null"u8);
98 | }
99 | else
100 | {
101 | var encodeValue = global::System.Web.HttpUtility.JavaScriptStringEncode(value);
102 | writer.Append(encodeValue);
103 | }
104 | }
105 | #endif
106 | }
107 |
108 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/StorageService/StorageItemValue.ToJavaScriptString.cs:
--------------------------------------------------------------------------------
1 | using System.Buffers;
2 | using System.Text;
3 | using Utf8StringInterpolation;
4 |
5 | namespace Avalonia.Controls;
6 |
7 | partial class WebView2
8 | {
9 | partial class StorageItemValue
10 | {
11 | internal static string ToJavaScriptString(
12 | params IEnumerable> pairs)
13 | {
14 | using var buffer = Utf8String.CreateWriter(out var writer);
15 | int i = 0;
16 | foreach (var it in pairs)
17 | {
18 | static bool WriteItemByType(ref Utf8StringWriter> writer, int i, KeyValuePair<(StorageItemType type, string key), StorageItemValue> it)
19 | {
20 | switch (it.Key.type)
21 | {
22 | case StorageItemType.LocalStorage:
23 | writer.AppendFormatted("local"u8);
24 | return true;
25 | case StorageItemType.SessionStorage:
26 | writer.AppendFormatted("session"u8);
27 | return true;
28 | case StorageItemType.AllStorage:
29 | switch (it.Value.operate)
30 | {
31 | case StorageItemOperate.SetItem:
32 | writer.AppendFormatted("let i"u8);
33 | writer.AppendFormatted(i);
34 | writer.AppendFormatted(" = \""u8);
35 | AppendValue(ref writer, it.Value);
36 | writer.AppendFormatted("\";"u8);
37 | writer.AppendFormatted("localStorage.setItem(\""u8);
38 | AppendKey(ref writer, it.Key.key);
39 | writer.AppendFormatted("\", i"u8);
40 | writer.AppendFormatted(i);
41 | writer.AppendFormatted(");"u8);
42 | writer.AppendFormatted("sessionStorage.setItem(\""u8);
43 | AppendKey(ref writer, it.Key.key);
44 | writer.AppendFormatted("\", i"u8);
45 | writer.AppendFormatted(i);
46 | writer.AppendFormatted(");"u8);
47 | break;
48 | case StorageItemOperate.RemoveItem:
49 | writer.AppendFormatted("localStorage.removeItem(\""u8);
50 | AppendJavaScriptStringEncode(ref writer, it.Key.key);
51 | writer.AppendFormatted("\");"u8);
52 | writer.AppendFormatted("sessionStorage.removeItem(\""u8);
53 | AppendJavaScriptStringEncode(ref writer, it.Key.key);
54 | writer.AppendFormatted("\");"u8);
55 | AppendKey(ref writer, it.Key.key);
56 | break;
57 | case StorageItemOperate.ClearAll:
58 | writer.AppendFormatted("localStorage.clear();sessionStorage.clear();"u8);
59 | break;
60 | }
61 | return false;
62 | }
63 | return false;
64 | }
65 |
66 | switch (it.Value.operate)
67 | {
68 | case StorageItemOperate.SetItem:
69 | if (!WriteItemByType(ref writer, i, it))
70 | {
71 | continue;
72 | }
73 | writer.AppendFormatted("Storage.setItem(\""u8);
74 | AppendKey(ref writer, it.Key.key);
75 | writer.AppendFormatted("\", \""u8);
76 | AppendValue(ref writer, it.Value);
77 | writer.AppendFormatted("\");"u8);
78 | break;
79 | case StorageItemOperate.RemoveItem:
80 | if (!WriteItemByType(ref writer, i, it))
81 | {
82 | continue;
83 | }
84 | writer.AppendFormatted("Storage.removeItem(\""u8);
85 | AppendJavaScriptStringEncode(ref writer, it.Key.key);
86 | writer.AppendFormatted("\");"u8);
87 | break;
88 | case StorageItemOperate.ClearAll:
89 | if (!WriteItemByType(ref writer, i, it))
90 | {
91 | continue;
92 | }
93 | writer.AppendFormatted("Storage.clear();"u8);
94 | break;
95 | }
96 | i++;
97 | }
98 | writer.Flush();
99 | #if NETFRAMEWORK || (NETSTANDARD && !NETSTANDARD2_1_OR_GREATER)
100 | var buffer2 = ArrayPool.Shared.Rent(buffer.WrittenSpan.Length);
101 | try
102 | {
103 | buffer.WrittenSpan.CopyTo(buffer2);
104 | var result = Encoding.UTF8.GetString(buffer2);
105 | return result;
106 | }
107 | finally
108 | {
109 | ArrayPool.Shared.Return(buffer2);
110 | }
111 | #else
112 | var result = Encoding.UTF8.GetString(buffer.WrittenSpan);
113 | return result;
114 | #endif
115 | }
116 | }
117 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/WebView2.Disposable.cs:
--------------------------------------------------------------------------------
1 | namespace Avalonia.Controls;
2 |
3 | partial class WebView2 : IDisposable
4 | {
5 | bool disposedValue;
6 | readonly List _disposables = [];
7 |
8 | ///
9 | /// 验证当前控件没有被释放,被释放后操作将抛出
10 | ///
11 | /// 当前控件被释放后操作引发
12 | void VerifyNotClosedGuard()
13 | {
14 | if (disposedValue)
15 | {
16 | throw new InvalidOperationException("The instance of CoreWebView2 is disposed and unable to complete this operation.");
17 | }
18 | }
19 |
20 | ///
21 | /// 是否已释放
22 | ///
23 | protected bool DisposedValue => disposedValue;
24 |
25 | ///
26 | protected virtual void Dispose(bool disposing)
27 | {
28 | if (!disposedValue)
29 | {
30 | if (disposing)
31 | {
32 | // 释放托管状态(托管对象)
33 | #if !DISABLE_WEBVIEW2_CORE && (WINDOWS || NETFRAMEWORK)
34 | UnsubscribeHandlersAndCloseController();
35 | #endif
36 | #if !(WINDOWS || NETFRAMEWORK) && NET8_0_OR_GREATER && !ANDROID && !IOS && !MACOS && !MACCATALYST && !DISABLE_CEFGLUE
37 | CefGuleDispose(disposing);
38 | #endif
39 | _disposables.ForEach(d => d.Dispose());
40 | }
41 |
42 | // 释放未托管的资源(未托管的对象)并重写终结器
43 | // 将大型字段设置为 null
44 | disposedValue = true;
45 | }
46 | }
47 |
48 | ///
49 | public void Dispose()
50 | {
51 | // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
52 | Dispose(disposing: true);
53 | GC.SuppressFinalize(this);
54 | }
55 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/WebView2.Properties/AllowExternalDrop.cs:
--------------------------------------------------------------------------------
1 | namespace Avalonia.Controls;
2 |
3 | partial class WebView2
4 | {
5 | bool _allowExternalDrop = true;
6 |
7 | ///
8 | /// Enable/disable external drop.
9 | /// 启用/禁用外部拖拽。
10 | ///
11 | public bool AllowExternalDrop
12 | {
13 | get
14 | {
15 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
16 | if (_coreWebView2Controller != null)
17 | {
18 | return _coreWebView2Controller.AllowExternalDrop;
19 | }
20 | #else
21 | // CEF_TODO: 待实现 AllowExternalDrop
22 | #endif
23 | return _allowExternalDrop;
24 | }
25 | set
26 | {
27 | if (_allowExternalDrop == value)
28 | {
29 | return;
30 | }
31 | _allowExternalDrop = value;
32 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
33 | _coreWebView2Controller?.AllowExternalDrop = value;
34 | #elif ANDROID
35 | #elif IOS
36 | #elif MACOS
37 | #else
38 | // CEF_TODO: 待实现 AllowExternalDrop
39 | #endif
40 | }
41 | }
42 |
43 | ///
44 | /// The which backs the property.
45 | ///
46 | public static readonly DirectProperty AllowExternalDropProperty = AvaloniaProperty.RegisterDirect(nameof(AllowExternalDrop), x => x._allowExternalDrop, (x, y) => x.AllowExternalDrop = y);
47 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/WebView2.Properties/CanGoBack.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace Avalonia.Controls;
4 |
5 | partial class WebView2
6 | {
7 | ///
8 | /// Returns if the can navigate to a previous page in the
9 | /// navigation history via the method.
10 | /// This is equivalent to the CoreWebView2.CanGoBack.
11 | /// If the underlying CoreWebView2 is not yet initialized, this property is .
12 | /// 如果 可以通过 方法导航到导航历史记录中的前一页,则返回
13 | /// 这等同于 CoreWebView2.CanGoBack
14 | /// 如果底层 CoreWebView2 尚未初始化,则此属性为
15 | ///
16 | [Browsable(false)]
17 | public bool CanGoBack
18 | {
19 | get
20 | {
21 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
22 | var coreWebView2 = CoreWebView2;
23 | if (coreWebView2 != null)
24 | {
25 | return coreWebView2.CanGoBack;
26 | }
27 | #elif ANDROID
28 | #elif IOS
29 | #elif MACOS
30 | #else
31 | // CEF_TODO: 待实现 CanGoBack
32 | #endif
33 | return false;
34 | }
35 | }
36 |
37 | ///
38 | /// The which backs the property.
39 | ///
40 | public static readonly DirectProperty CanGoBackProperty = AvaloniaProperty.RegisterDirect(nameof(CanGoBack), x => x.CanGoBack);
41 |
42 | ///
43 | /// Navigates to the previous page in navigation history.
44 | /// This is equivalent to CoreWebView2.GoBack.
45 | /// If the underlying WebView2.CoreWebView2 is not yet initialized, this method does nothing.
46 | ///
47 | public void GoBack()
48 | {
49 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
50 | CoreWebView2?.GoBack();
51 | #elif ANDROID
52 | #elif IOS
53 | #else
54 | // CEF_TODO: 待实现 GoBack
55 | #endif
56 | }
57 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/WebView2.Properties/CanGoForward.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace Avalonia.Controls;
4 |
5 | partial class WebView2
6 | {
7 | ///
8 | /// Returns if the can navigate to a next page in the
9 | /// navigation history via the method.
10 | /// This is equivalent to the CoreWebView2.CanGoForward.
11 | /// If the underlying CoreWebView2 is not yet initialized, this property is false.
12 | /// 如果 可以通过 方法导航到导航历史记录中的下一页,则返回 。
13 | /// 这等同于 CoreWebView2.CanGoForward 方法。
14 | /// 如果底层 CoreWebView2 尚未初始化,则此属性为
15 | ///
16 | [Browsable(false)]
17 | public bool CanGoForward
18 | {
19 | get
20 | {
21 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
22 | var coreWebView2 = CoreWebView2;
23 | if (coreWebView2 != null)
24 | {
25 | return coreWebView2.CanGoForward;
26 | }
27 | #elif ANDROID
28 | #elif IOS
29 | #else
30 | // CEF_TODO: 待实现 CanGoForward
31 | #endif
32 | return false;
33 | }
34 | }
35 |
36 | ///
37 | /// The which backs the property.
38 | ///
39 | public static readonly DirectProperty CanGoForwardProperty = AvaloniaProperty.RegisterDirect(nameof(CanGoForward), x => x.CanGoForward);
40 |
41 | ///
42 | /// Navigates to the next page in navigation history.
43 | /// This is equivalent to CoreWebView2.GoForward.
44 | /// If the underlying WebView2.CoreWebView2 is not yet initialized, this method does nothing.
45 | ///
46 | ///
47 | public void GoForward()
48 | {
49 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
50 | CoreWebView2?.GoForward();
51 | #elif ANDROID
52 | #elif IOS
53 | #else
54 | // CEF_TODO: 待实现 GoForward
55 | #endif
56 | }
57 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/WebView2.Properties/Cookies.cs:
--------------------------------------------------------------------------------
1 | //using System.Net;
2 |
3 | //namespace Avalonia.Controls;
4 |
5 | //partial class WebView2
6 | //{
7 | // ///
8 | // /// When set this will act as a sync for cookies.
9 | // ///
10 | // public CookieContainer Cookies
11 | // {
12 | // get
13 | // {
14 | // // TODO: 尚未实现
15 | // throw new NotImplementedException();
16 | // }
17 | // }
18 | //}
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/WebView2.Properties/CreationProperties.cs:
--------------------------------------------------------------------------------
1 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
2 | using System.ComponentModel;
3 |
4 | namespace Avalonia.Controls;
5 |
6 | partial class WebView2
7 | {
8 | CoreWebView2CreationProperties? _creationProperties;
9 |
10 | ///
11 | /// Gets or sets a bag of options which are used during initialization of the control's WebView2.CoreWebView2.
12 | /// This property cannot be modified (an exception will be thrown) after initialization of the control's CoreWebView2 has started.
13 | /// 获取或设置在初始化控件 WebView2.CoreWebView2 时使用的一组选项。
14 | /// 在控件的 CoreWebView2 初始化开始后,该属性不可修改(会出现异常)。
15 | ///
16 | ///
17 | /// Thrown if initialization of the control's CoreWebView2 has already started.
18 | /// 如果控件的 CoreWebView2 已开始初始化,则抛出该抛掷值。
19 | ///
20 | [Browsable(false)]
21 | public CoreWebView2CreationProperties? CreationProperties
22 | {
23 | get => _creationProperties;
24 | set
25 | {
26 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
27 | if (_initTask != null)
28 | {
29 | // 在 CoreWebView2 初始化开始后,不能修改 CreationProperties
30 | throw new InvalidOperationException(
31 | "CreationProperties cannot be modified after the initialization of CoreWebView2 has begun.");
32 | }
33 | #endif
34 | _creationProperties = value;
35 | }
36 | }
37 |
38 | ///
39 | /// The which backs the property.
40 | ///
41 | ///
42 | public static readonly DirectProperty CreationPropertiesProperty = AvaloniaProperty.RegisterDirect(nameof(CreationProperties),
43 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
44 | x => x.env != null ? x._creationProperties : null,
45 | #else
46 | x => x._creationProperties,
47 | #endif
48 | (x, y) => x.CreationProperties = y);
49 | }
50 | #endif
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/WebView2.Properties/DefaultBackgroundColor.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls.Shapes;
2 | using Avalonia.Media.Immutable;
3 | using System.Drawing;
4 |
5 | namespace Avalonia.Controls;
6 |
7 | partial class WebView2
8 | {
9 | ///
10 | /// 默认背景颜色,白色
11 | ///
12 | static readonly Color _defaultBackgroundColorDefaultValue = Color.White;
13 |
14 | Color _defaultBackgroundColor;
15 |
16 | void SetDefaultBackgroundColor(Color value)
17 | {
18 | _defaultBackgroundColor = value;
19 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
20 | if (_coreWebView2Controller == null)
21 | {
22 | }
23 | else
24 | {
25 | _coreWebView2Controller.DefaultBackgroundColor = value;
26 | }
27 | #elif ANDROID
28 | #elif IOS
29 | #else
30 | // CEF_TODO: 待实现 DefaultBackgroundColor
31 | #endif
32 | var avaColor =
33 | global::Avalonia.Media.Color.FromArgb(value.A, value.R, value.G, value.B);
34 | if ((object?)this is Shape shape)
35 | {
36 | shape.Fill = new ImmutableSolidColorBrush(avaColor);
37 | }
38 | }
39 |
40 | ///
41 | /// 的默认背景颜色
42 | ///
43 | public Color DefaultBackgroundColor
44 | {
45 | get
46 | {
47 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
48 | if (_coreWebView2Controller != null)
49 | {
50 | return _coreWebView2Controller.DefaultBackgroundColor;
51 | }
52 | #elif ANDROID
53 | #elif IOS
54 | #else
55 | // CEF_TODO: 待实现 DefaultBackgroundColor
56 | #endif
57 | return _defaultBackgroundColor;
58 | }
59 |
60 | set
61 | {
62 | if (value == _defaultBackgroundColor)
63 | {
64 | return;
65 | }
66 | SetDefaultBackgroundColor(value);
67 | }
68 | }
69 |
70 | ///
71 | /// The which backs the property.
72 | ///
73 | public static readonly DirectProperty DefaultBackgroundColorProperty = AvaloniaProperty.RegisterDirect(nameof(DefaultBackgroundColor), x => x._defaultBackgroundColor, (x, y) => x.DefaultBackgroundColor = y);
74 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/WebView2.Properties/HtmlSource.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace Avalonia.Controls;
4 |
5 | partial class WebView2
6 | {
7 | string? _htmlSource;
8 |
9 | ///
10 | /// HtmlSource 属性是 WebView2 顶层文档的 HTML 内容字符串
11 | /// 总大小不得超过 2 MB(2 * 1024 * 1024 字节)
12 | /// 设置源相当于调用 CoreWebView2.Navigate 设置源将触发 CoreWebView2 的初始化(如果尚未初始化)
13 | /// HtmlSource 的默认值为 ,表示 CoreWebView2 尚未初始化
14 | ///
15 | [Browsable(true)]
16 | public string? HtmlSource
17 | {
18 | get => _htmlSource;
19 | set
20 | {
21 | if (value == null)
22 | {
23 | if (_htmlSource == null)
24 | {
25 | return;
26 | }
27 | else
28 | {
29 | // 行为更变:源 WebView2 Wpf 中会抛出 new NotImplementedException("The HtmlSource property cannot be set to null."),改为空字符串避免 catch
30 | value = string.Empty;
31 | }
32 | }
33 | else
34 | {
35 | if (_htmlSource == null || _htmlSource != value)
36 | {
37 | _source = null;
38 | SetAndRaise(HtmlSourceProperty, ref _htmlSource, value);
39 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
40 | CoreWebView2?.NavigateToString(value);
41 | #elif ANDROID
42 | var aWebView = AWebView;
43 | if (aWebView != null)
44 | {
45 | aWebView.LoadData(value, "text/html", "UTF-8");
46 | }
47 | #elif IOS
48 | var wkWebView = WKWebView;
49 | if (wkWebView != null)
50 | {
51 | wkWebView.LoadHtmlString(value, (NSUrl?)null!);
52 | }
53 | #else
54 | // CEF_TODO: 待实现 NavigateToString
55 | #endif
56 | }
57 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
58 | _implicitInitGate.RunWhenOpen(() => EnsureCoreWebView2Async());
59 | #endif
60 | }
61 | }
62 | }
63 |
64 | ///
65 | /// The which backs the property.
66 | ///
67 | public static readonly DirectProperty HtmlSourceProperty = AvaloniaProperty.RegisterDirect(nameof(HtmlSource), x => x._htmlSource, (x, y) => x.HtmlSource = y);
68 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/WebView2.Properties/Source.cs:
--------------------------------------------------------------------------------
1 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
2 | using Microsoft.Web.WebView2.Core;
3 | #endif
4 | using System.ComponentModel;
5 | using System.Net.Http;
6 |
7 | namespace Avalonia.Controls;
8 |
9 | partial class WebView2
10 | {
11 | Uri? _source;
12 |
13 | ///
14 | /// Source 属性是 WebView2 顶层文档的
15 | /// 设置源相当于调用 CoreWebView2.Navigate 设置源将触发 CoreWebView2 的初始化(如果尚未初始化)
16 | /// Source 的默认值为 ,表示 CoreWebView2 尚未初始化
17 | ///
18 | /// 指定 值不是
19 | [Browsable(true)]
20 | public Uri? Source
21 | {
22 | get => _source;
23 | set
24 | {
25 | if (value == null)
26 | {
27 | if (_source == null)
28 | {
29 | return;
30 | }
31 | else
32 | {
33 | // 行为更变:源 WebView2 Wpf 中会抛出 new NotImplementedException("The Source property cannot be set to null."),改为跳转空白页避免 catch
34 | value = new Uri("about:blank", UriKind.Absolute);
35 | }
36 | }
37 | else if (!value.IsAbsoluteUri)
38 | {
39 | throw new ArgumentException("Only absolute URI is allowed", "Source");
40 | }
41 | else if (_source == null || _source.AbsoluteUri != value.AbsoluteUri)
42 | {
43 | _htmlSource = null;
44 | SetAndRaise(SourceProperty, ref _source, value);
45 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
46 | if (CoreWebView2 != null)
47 | {
48 | if (value is WebResourceRequestUri webResourceRequest)
49 | {
50 | CoreWebView2.NavigateWithWebResourceRequest(webResourceRequest.ToRequest(CoreWebView2.Environment));
51 | }
52 | else
53 | {
54 | CoreWebView2.Navigate(value.AbsoluteUri);
55 | }
56 | }
57 | #elif ANDROID
58 | var aWebView = AWebView;
59 | if (aWebView != null)
60 | {
61 | aWebView.LoadUrl(value.AbsoluteUri);
62 | }
63 | #elif IOS
64 | var wkWebView = WKWebView;
65 | if (wkWebView != null)
66 | {
67 | NSUrl nsUrl = new(value.AbsoluteUri);
68 | NSUrlRequest nsUrlRequest = new(nsUrl);
69 | wkWebView.LoadRequest(nsUrlRequest);
70 | }
71 | #else
72 | // CEF_TODO: 待实现 Navigate
73 | #endif
74 | }
75 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
76 | _implicitInitGate.RunWhenOpen(() => EnsureCoreWebView2Async());
77 | #endif
78 | }
79 | }
80 |
81 | ///
82 | /// 与 WebResourceRequested 事件一起使用的 HTTP 请求,继承自 ,可自定义响应内容并赋值给属性 ,默认 为
83 | /// 示例:https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2.navigatewithwebresourcerequest
84 | ///
85 | public sealed class WebResourceRequestUri(string uriString, Stream? content, HttpMethod? method = null) : Uri(uriString, UriKind.Absolute)
86 | {
87 | readonly string uriString = uriString;
88 |
89 | ///
90 | /// 以流形式获取或设置 HTTP 请求消息正文
91 | ///
92 | public Stream? Content { get; set; } = content;
93 |
94 | ///
95 | /// 获取或设置可变 HTTP 请求头
96 | /// 示例值:Content-Type: application/x-www-form-urlencoded\r\n
97 | /// https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2.navigatewithwebresourcerequest
98 | ///
99 | public string? Headers { get; set; }
100 |
101 | ///
102 | /// HTTP 请求方法
103 | ///
104 | public HttpMethod? Method { get; set; } = method;
105 |
106 | internal static string GetMethod(HttpMethod? method) => (method ?? HttpMethod.Get).Method;
107 |
108 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
109 | internal CoreWebView2WebResourceRequest ToRequest(CoreWebView2Environment env)
110 | {
111 | var result = env.CreateWebResourceRequest(uriString,
112 | GetMethod(Method),
113 | Content,
114 | Headers);
115 | return result;
116 | }
117 | #endif
118 | }
119 |
120 | ///
121 | /// The which backs the property.
122 | ///
123 | public static readonly DirectProperty SourceProperty = AvaloniaProperty.RegisterDirect(nameof(Source), x => x._source, (x, y) => x.Source = y);
124 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/WebView2.Properties/Storages.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Platform.Storage;
2 |
3 | namespace Avalonia.Controls;
4 |
5 | partial class WebView2
6 | {
7 | ///
8 | public IStorageService? StorageService { get; set; }
9 |
10 | ///
11 | /// 处理注入 Web Storage 生成的 JS 内容
12 | ///
13 | protected static string? HandlerStorageServiceGenerateJSString(IStorageService? storageService, string requestUri)
14 | {
15 | if (storageService != null)
16 | {
17 | var value = storageService.GetStorages(requestUri);
18 | if (value != null)
19 | {
20 | var js = StorageItemValue.ToJavaScriptString(value);
21 | if (!string.IsNullOrWhiteSpace(js))
22 | {
23 | return js;
24 | }
25 | }
26 | }
27 | return null;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/WebView2.Properties/UserAgent.cs:
--------------------------------------------------------------------------------
1 | //namespace Avalonia.Controls;
2 |
3 | //partial class WebView2
4 | //{
5 | // ///
6 | // /// Gets or sets the WebView's user agent string.
7 | // ///
8 | // public string? UserAgent
9 | // {
10 | // get
11 | // {
12 | // // TODO: 尚未实现
13 | // throw new NotImplementedException();
14 | // }
15 |
16 | // set
17 | // {
18 |
19 | // // TODO: 尚未实现
20 | // throw new NotImplementedException();
21 | // }
22 | // }
23 | //}
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/WebView2.Properties/ZoomFactor.cs:
--------------------------------------------------------------------------------
1 | namespace Avalonia.Controls;
2 |
3 | partial class WebView2
4 | {
5 | double _zoomFactor = 1.0;
6 |
7 | ///
8 | /// The zoom factor for the WebView.
9 | /// WebView 的缩放系数。
10 | ///
11 | public double ZoomFactor
12 | {
13 | get
14 | {
15 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
16 | if (_coreWebView2Controller != null)
17 | {
18 | return _coreWebView2Controller.ZoomFactor;
19 | }
20 | #elif ANDROID
21 | #elif IOS
22 | #else
23 | // CEF_TODO: 待实现 ZoomFactor
24 | #endif
25 | return _zoomFactor;
26 | }
27 | set
28 | {
29 | if (_zoomFactor == value)
30 | {
31 | return;
32 | }
33 | _zoomFactor = value;
34 | #if !DISABLE_WEBVIEW2_CORE && WINDOWS || NETFRAMEWORK
35 | _coreWebView2Controller?.ZoomFactor = value;
36 | #elif ANDROID
37 | #elif IOS
38 | #else
39 | // CEF_TODO: 待实现 ZoomFactor
40 | #endif
41 | }
42 | }
43 |
44 | ///
45 | /// The which backs the property.
46 | ///
47 | public static readonly DirectProperty ZoomFactorProperty = AvaloniaProperty.RegisterDirect(nameof(ZoomFactor), x => x._zoomFactor, (x, y) => x.ZoomFactor = y);
48 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/WebView2.Script.cs:
--------------------------------------------------------------------------------
1 | //using System;
2 | //using System.Collections.Generic;
3 | //using System.Collections.Specialized;
4 | //using System.Text;
5 | //using System.Web;
6 |
7 | //namespace Avalonia.Controls;
8 |
9 | //partial class WebView2
10 | //{
11 |
12 | // WebView2OnDocumentCreatedLoader? _documentCreatedLoader;
13 |
14 | // ///
15 | // /// WebView2 DocumentCreated Loader
16 | // ///
17 | // public WebView2OnDocumentCreatedLoader? DocumentCreatedLoader { get => _documentCreatedLoader; set { _documentCreatedLoader = value; } }
18 |
19 | // ///
20 | // /// 添加 JavaScript 到 WebView2 的 DocumentCreated 事件中。
21 | // ///
22 | // ///
23 | // ///
24 | // ///
25 | // public async Task AddScriptToExecuteOnDocumentCreatedAsync(string js)
26 | // {
27 | //#if !DISABLE_WEBVIEW2_CORE && (WINDOWS || NETFRAMEWORK)
28 | // if (_coreWebView2Controller != null)
29 | // {
30 | // return await _coreWebView2Controller.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(js);
31 | // }
32 | //#endif
33 | // throw new ArgumentNullException();
34 | // }
35 |
36 | // ///
37 | // /// 加载需要载入的 JavaScript 到 WebView2 的 DocumentCreated 事件中。
38 | // ///
39 | // ///
40 | // internal async Task InitJavaScriptOnDocumentCreatedAsync()
41 | // {
42 | // if (_documentCreatedLoader is not null)
43 | // {
44 | // if (_documentCreatedLoader.SessionStorage != null)
45 | // {
46 | // var sessionStorage = new NameValueCollection();
47 | // _documentCreatedLoader.SessionStorage(sessionStorage);
48 | // await AddSessionStorageOnDocumentCreatedAsync(sessionStorage);
49 | // }
50 | // if (_documentCreatedLoader.LocalStorage != null)
51 | // {
52 | // var localStorage = new NameValueCollection();
53 | // _documentCreatedLoader.LocalStorage(localStorage);
54 | // await AddLocalStorageOnDocumentCreatedAsync(localStorage);
55 | // }
56 | // }
57 | // }
58 |
59 | // ///
60 | // /// 添加 LocalStorage 到 WebView2 的 DocumentCreated 事件中。
61 | // ///
62 | // ///
63 | // ///
64 | // internal async Task AddLocalStorageOnDocumentCreatedAsync(NameValueCollection localStorage)
65 | // => await SetStorageAsync(localStorageSetFormatter, localStorage);
66 |
67 | // internal async Task AddSessionStorageOnDocumentCreatedAsync(NameValueCollection sessionStorage)
68 | // => await SetStorageAsync(sessionStorageSetFormatter, sessionStorage);
69 |
70 | // static string localStorageSetFormatter = "localStorage.setItem('{0}', `{1}`);";
71 | // static string sessionStorageSetFormatter = "sessionStorage.setItem('{0}', `{1}`);";
72 |
73 | // private async Task SetStorageAsync(string stringFormatter, NameValueCollection collection)
74 | // {
75 | //#if !DISABLE_WEBVIEW2_CORE && (WINDOWS || NETFRAMEWORK)
76 | // if (_coreWebView2Controller != null)
77 | // {
78 |
79 | // foreach (var key in collection.AllKeys)
80 | // {
81 | // var value = collection[key];
82 | // var js = string.Format(stringFormatter, key, value);
83 | // await _coreWebView2Controller.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(js);
84 | // }
85 | // return true;
86 | // }
87 | //#endif
88 | // return false;
89 | // }
90 |
91 | // ///
92 | // /// WebView2 DocumentCreated Loader,for example SessionStorage 和 LocalStorage。
93 | // ///
94 | // public class WebView2OnDocumentCreatedLoader
95 | // {
96 | // ///
97 | // /// SessionStorage Load OnDocumentCreated.
98 | // ///
99 | // public Action? SessionStorage { get; set; }
100 |
101 | // ///
102 | // /// LocalStorage Load OnDocumentCreated.
103 | // ///
104 | // public Action? LocalStorage { get; set; }
105 | // }
106 | //}
107 |
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/WebView2.VisualTree.cs:
--------------------------------------------------------------------------------
1 | namespace Avalonia.Controls;
2 |
3 | partial class WebView2
4 | {
5 | TaskCompletionSource _hwndTaskSource = new();
6 |
7 | ///
8 | /// 当前控件所在的窗口,如果没有,则为
9 | ///
10 | protected Window? Window { get; set; }
11 |
12 | void Window_Closed(object? sender, EventArgs e)
13 | {
14 | // 当窗口关闭时,释放控件
15 | Dispose();
16 | }
17 |
18 | ///
19 | protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
20 | {
21 | if (e.Root is Window window)
22 | {
23 | var prevWindow = Window;
24 | var isSameWindow = prevWindow == window;
25 | if (prevWindow != null)
26 | {
27 | if (!isSameWindow)
28 | {
29 | // 移除上一个窗口的 Closed 事件
30 | prevWindow.Closed -= Window_Closed;
31 | }
32 | }
33 | if (!isSameWindow)
34 | {
35 | // Different windows cannot be reinitialized successfully
36 | Window = window;
37 | Window.Closed += Window_Closed;
38 | var hwnd = window.TryGetPlatformHandle()?.Handle;
39 | if (hwnd.HasValue && hwnd.Value != default)
40 | {
41 | if (!_hwndTaskSource.TrySetResult(hwnd.Value))
42 | {
43 | TaskCompletionSource hwndTaskSource = new();
44 | hwndTaskSource.SetResult(hwnd.Value);
45 | _hwndTaskSource = hwndTaskSource;
46 | }
47 | }
48 | #if !DISABLE_WEBVIEW2_CORE && (WINDOWS || NETFRAMEWORK)
49 | _implicitInitGate.OnSynchronizationContextExists();
50 | #endif
51 | }
52 | }
53 | #if !DISABLE_WEBVIEW2_CORE && (WINDOWS || NETFRAMEWORK)
54 | if (_coreWebView2Controller != null)
55 | {
56 | if (!_coreWebView2Controller.IsVisible)
57 | {
58 | _coreWebView2Controller.IsVisible = true;
59 | }
60 | }
61 | #endif
62 | base.OnAttachedToVisualTree(e);
63 | }
64 |
65 | ///
66 | protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
67 | {
68 | base.OnDetachedFromVisualTree(e);
69 | #if !DISABLE_WEBVIEW2_CORE && (WINDOWS || NETFRAMEWORK)
70 | if (_coreWebView2Controller != null)
71 | {
72 | if (_coreWebView2Controller.IsVisible)
73 | {
74 | // 当控件在虚拟树中 Detached 时,隐藏 CoreWebView2
75 | _coreWebView2Controller.IsVisible = false;
76 | }
77 | }
78 | #endif
79 | }
80 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Controls/WebView2.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Input;
2 |
3 | namespace Avalonia.Controls;
4 |
5 | ///
6 | /// Microsoft Edge WebView2 控件允许您在本地应用程序中嵌入网络技术(HTML、CSS 和 JavaScript)。WebView2 控件使用 Microsoft Edge 作为渲染引擎,在本地应用程序中显示网页内容。使用 WebView2,您可以在本地应用程序的不同部分嵌入网页代码,或者在一个 WebView2 实例中构建所有本地应用程序。
7 | ///
8 | public partial class WebView2
9 | {
10 | static WebView2()
11 | {
12 | #if WINDOWS && !DISABLE_WEBVIEW2_CORE
13 | RefreshIsSupported();
14 | #endif
15 | }
16 |
17 | ///
18 | public WebView2()
19 | {
20 | if (IsInDesignMode)
21 | {
22 | // 在设计器中不工作
23 | return;
24 | }
25 | // 添加控件显示隐藏切时通知 CoreWebView2Controller
26 | _disposables.Add(this.GetPropertyChangedObservable(IsVisibleProperty).AddClassHandler((t, args) => { IsVisibleChanged(args); }));
27 | SetDefaultBackgroundColor(_defaultBackgroundColorDefaultValue);
28 |
29 |
30 | #if !(WINDOWS || NETFRAMEWORK) && NET8_0_OR_GREATER && !ANDROID && !IOS && !MACOS && !MACCATALYST && !DISABLE_CEFGLUE
31 | CefGuleInitialize();
32 | #endif
33 | }
34 |
35 | ///
36 | protected override void OnInitialized()
37 | {
38 | base.OnInitialized();
39 |
40 | #if WINDOWS || NETFRAMEWORK
41 | global::CefNet.Internal.GlobalHooks.Initialize(this);
42 | #endif
43 | }
44 |
45 | ///
46 | /// This is a handler for our base UIElement's IsVisibleChanged event.
47 | /// It's predictably fired whenever IsVisible changes, and IsVisible reflects the actual current visibility status of the control.
48 | /// We just need to pass this info through to our CoreWebView2Controller so it can save some effort when the control isn't visible.
49 | ///
50 | protected virtual void IsVisibleChanged(EventArgs e)
51 | {
52 | #if !DISABLE_WEBVIEW2_CORE && (WINDOWS || NETFRAMEWORK)
53 | if (_coreWebView2Controller == null)
54 | return;
55 | _coreWebView2Controller.IsVisible = IsVisible;
56 | #endif
57 | }
58 |
59 | ///
60 | protected override void OnGotFocus(GotFocusEventArgs e)
61 | {
62 | base.OnGotFocus(e);
63 | #if !DISABLE_WEBVIEW2_CORE && (WINDOWS || NETFRAMEWORK)
64 | if (_coreWebView2Controller != null)
65 | {
66 | if (!_browserCrashed)
67 | {
68 | try
69 | {
70 | _coreWebView2Controller.MoveFocus(_lastMoveFocusReason);
71 | }
72 | catch (InvalidOperationException ex)
73 | {
74 | if (ex.InnerException != null && ex.InnerException.HResult != -2147019873)
75 | {
76 | throw;
77 | }
78 | }
79 | }
80 | }
81 | _lastMoveFocusReason = global::Microsoft.Web.WebView2.Core.CoreWebView2MoveFocusReason.Programmatic;
82 | #endif
83 | }
84 |
85 | ///
86 | /// True when we're in design mode and shouldn't create an underlying CoreWebView2.
87 | /// 为 时,我们处于设计模式,不应创建底层 CoreWebView2
88 | ///
89 | protected static bool IsInDesignMode => Design.IsDesignMode;
90 | }
91 |
92 | #if !(WINDOWS || NETFRAMEWORK) && !NET8_0_OR_GREATER && !(ANDROID || IOS || MACCATALYST || MACOS)
93 | partial class WebView2 : global::Avalonia.Controls.Shapes.Rectangle
94 | {
95 | }
96 | #endif
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Input/WebView2KeyEventArgs.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Controls;
2 |
3 | namespace Avalonia.Input;
4 |
5 | ///
6 | /// 控件的键盘输入事件参数
7 | ///
8 | public partial class WebView2KeyEventArgs : KeyEventArgs
9 | {
10 | public long Timestamp { get; } =
11 | #if NETCOREAPP3_0_OR_GREATER
12 | Environment.TickCount64;
13 | #else
14 | Environment.TickCount;
15 | #endif
16 |
17 | public WebView2KeyEventArgs(Key key)
18 | {
19 | Key = key;
20 | }
21 | }
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/NativeMethods.txt:
--------------------------------------------------------------------------------
1 | BeginPaint
2 | EndPaint
3 | CreateWindowExW
4 | DestroyWindow
5 | ShowWindow
6 | GetWindowThreadProcessId
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Platforms/CefGlue/Controls/WebView2.AvaloniaCefBrowser.EventHandlers.Subscribe.cs:
--------------------------------------------------------------------------------
1 | #if !(WINDOWS || NETFRAMEWORK) && NET8_0_OR_GREATER && !ANDROID && !IOS && !MACOS && !MACCATALYST && !DISABLE_CEFGLUE
2 |
3 | namespace Avalonia.Controls;
4 |
5 | partial class WebView2
6 | {
7 | ///
8 | /// 订阅 WebView2 控件的事件处理程序
9 | ///
10 | void SubscribeHandlers()
11 | {
12 | this.LoadStart += OnBrowserLoadStart;
13 | }
14 |
15 | ///
16 | /// 取消订阅 WebView2 控件的事件处理程序
17 | ///
18 | void UnsubscribeHandlers()
19 | {
20 | this.LoadStart -= OnBrowserLoadStart;
21 | }
22 | }
23 | #endif
--------------------------------------------------------------------------------
/src/Avalonia.WebView2/Platforms/CefGlue/Controls/WebView2.AvaloniaCefBrowser.EventHandlers.cs:
--------------------------------------------------------------------------------
1 | #if !(WINDOWS || NETFRAMEWORK) && NET8_0_OR_GREATER && !ANDROID && !IOS && !MACOS && !MACCATALYST && !DISABLE_CEFGLUE
2 |
3 | using Xilium.CefGlue.Common.Events;
4 |
5 | namespace Avalonia.Controls;
6 |
7 | partial class WebView2
8 | {
9 | void OnBrowserLoadStart(object sender, LoadStartEventArgs e)
10 | {
11 | try
12 | {
13 | var contentLoading = ContentLoading;
14 | if (contentLoading == null)
15 | {
16 | return;
17 | }
18 | contentLoading(this, e);
19 | }
20 | finally
21 | {
22 | var requestUri = e.Frame.Url;
23 | var js = HandlerStorageServiceGenerateJSString(StorageService, requestUri);
24 | if (js != null)
25 | {
26 | EvaluateJavaScript