Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 
 
 

336 Zeilen
11 KiB

  1. //
  2. // Created by yangbin on 2021/11/12.
  3. //
  4. #include <windows.h>
  5. #include <tchar.h>
  6. #include <cassert>
  7. #include <iostream>
  8. #include <utility>
  9. #include <thread>
  10. #include "web_view.h"
  11. #include "utils.h"
  12. #include "strconv.h"
  13. namespace webview_window {
  14. static LRESULT CALLBACK WndProc(HWND const window,
  15. UINT const message,
  16. WPARAM const wparam,
  17. LPARAM const lparam) noexcept {
  18. return DefWindowProc(window, message, wparam, lparam);
  19. }
  20. const auto kWebViewClassName = _T("web_view_window_web_view");
  21. using namespace Microsoft::WRL;
  22. WebView::WebView(
  23. std::shared_ptr<flutter::MethodChannel<flutter::EncodableValue>> method_channel,
  24. int64_t web_view_id, std::wstring userDataFolder,
  25. std::function<void(HRESULT)> on_web_view_created
  26. ) : method_channel_(std::move(method_channel)),
  27. web_view_id_(web_view_id), user_data_folder_(std::move(userDataFolder)),
  28. on_web_view_created_callback_(std::move(on_web_view_created)) {
  29. RegisterWindowClass(kWebViewClassName, WndProc);
  30. view_window_ = wil::unique_hwnd(::CreateWindowEx(
  31. 0,
  32. kWebViewClassName,
  33. L"",
  34. WS_CHILD | WS_VISIBLE,
  35. 0,
  36. 0,
  37. 0,
  38. 0,
  39. HWND_MESSAGE,
  40. nullptr,
  41. ::GetModuleHandle(nullptr),
  42. nullptr));
  43. assert(view_window_ != nullptr);
  44. if (!view_window_) {
  45. on_web_view_created_callback_(S_FALSE);
  46. return;
  47. }
  48. CreateCoreWebView2EnvironmentWithOptions(
  49. nullptr, user_data_folder_.c_str(), nullptr,
  50. Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>(
  51. [this](HRESULT result, ICoreWebView2Environment *env) -> HRESULT {
  52. if (!SUCCEEDED(result)) {
  53. on_web_view_created_callback_(result);
  54. return S_OK;
  55. }
  56. env->CreateCoreWebView2Controller(
  57. view_window_.get(),
  58. Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>(
  59. [this](HRESULT result, ICoreWebView2Controller *controller) -> HRESULT {
  60. on_web_view_created_callback_(result);
  61. if (SUCCEEDED(result)) {
  62. webview_controller_ = controller;
  63. OnWebviewControllerCreated();
  64. }
  65. return S_OK;
  66. }).Get());
  67. return S_OK;
  68. }).Get());
  69. }
  70. void WebView::OnWebviewControllerCreated() {
  71. if (!webview_controller_) {
  72. return;
  73. }
  74. webview_controller_->get_CoreWebView2(&webview_);
  75. if (!webview_) {
  76. std::cerr << "failed to get core webview" << std::endl;
  77. return;
  78. }
  79. ICoreWebView2Settings *settings;
  80. webview_->get_Settings(&settings);
  81. settings->put_IsScriptEnabled(true);
  82. settings->put_IsZoomControlEnabled(false);
  83. settings->put_AreDefaultContextMenusEnabled(false);
  84. settings->put_IsStatusBarEnabled(false);
  85. settings->put_IsWebMessageEnabled(true);
  86. ICoreWebView2Settings2 *settings2;
  87. auto hr = settings->QueryInterface(IID_PPV_ARGS(&settings2));
  88. if (SUCCEEDED(hr)) {
  89. LPWSTR user_agent[256];
  90. settings2->get_UserAgent(user_agent);
  91. default_user_agent_ = std::wstring(*user_agent);
  92. }
  93. UpdateBounds();
  94. // Always use single window to load web page.
  95. webview_->add_NewWindowRequested(
  96. Callback<ICoreWebView2NewWindowRequestedEventHandler>(
  97. [](ICoreWebView2 *sender, ICoreWebView2NewWindowRequestedEventArgs *args) {
  98. LPWSTR url;
  99. args->get_Uri(&url);
  100. sender->Navigate(url);
  101. args->put_Handled(true);
  102. return S_OK;
  103. }).Get(), nullptr);
  104. webview_->add_ContentLoading(
  105. Callback<ICoreWebView2ContentLoadingEventHandler>(
  106. [](ICoreWebView2 *sender, ICoreWebView2ContentLoadingEventArgs *args) {
  107. return S_OK;
  108. }).Get(), nullptr);
  109. webview_->add_HistoryChanged(
  110. Callback<ICoreWebView2HistoryChangedEventHandler>(
  111. [this](ICoreWebView2 *sender, IUnknown *args) {
  112. auto method_args = flutter::EncodableMap{
  113. {flutter::EncodableValue("id"), flutter::EncodableValue(web_view_id_)},
  114. {flutter::EncodableValue("canGoBack"), flutter::EncodableValue(CanGoBack())},
  115. {flutter::EncodableValue("canGoForward"), flutter::EncodableValue(CanGoForward())},
  116. };
  117. method_channel_->InvokeMethod("onHistoryChanged",
  118. std::make_unique<flutter::EncodableValue>(method_args));
  119. return S_OK;
  120. }
  121. ).Get(), nullptr);
  122. webview_->add_NavigationStarting(
  123. Callback<ICoreWebView2NavigationStartingEventHandler>(
  124. [this](ICoreWebView2 *sender, ICoreWebView2NavigationStartingEventArgs *args) {
  125. method_channel_->InvokeMethod(
  126. "onNavigationStarted",
  127. std::make_unique<flutter::EncodableValue>(flutter::EncodableMap{
  128. {flutter::EncodableValue("id"), flutter::EncodableValue(web_view_id_)},
  129. }));
  130. LPWSTR uri;
  131. args->get_Uri(&uri);
  132. method_channel_->InvokeMethod(
  133. "onUrlRequested",
  134. std::make_unique<flutter::EncodableValue>(flutter::EncodableMap{
  135. {flutter::EncodableValue("id"), flutter::EncodableValue(web_view_id_)},
  136. {flutter::EncodableValue("url"), flutter::EncodableValue(wide_to_utf8(std::wstring(uri)))},
  137. }));
  138. return S_OK;
  139. }
  140. ).Get(), nullptr);
  141. webview_->add_NavigationCompleted(
  142. Callback<ICoreWebView2NavigationCompletedEventHandler>(
  143. [this](ICoreWebView2 *sender, ICoreWebView2NavigationCompletedEventArgs *args) {
  144. auto method_args = flutter::EncodableMap{
  145. {flutter::EncodableValue("id"), flutter::EncodableValue(web_view_id_)},
  146. };
  147. method_channel_->InvokeMethod("onNavigationCompleted",
  148. std::make_unique<flutter::EncodableValue>(method_args));
  149. return S_OK;
  150. }
  151. ).Get(), nullptr);
  152. webview_->add_WebMessageReceived(
  153. Callback<ICoreWebView2WebMessageReceivedEventHandler>(
  154. [this](ICoreWebView2 *sender, ICoreWebView2WebMessageReceivedEventArgs *args) {
  155. wil::unique_cotaskmem_string messageRaw;
  156. HRESULT hrString = args->TryGetWebMessageAsString(&messageRaw);
  157. if (FAILED(hrString)) {
  158. if (hrString == E_INVALIDARG) {
  159. // web message was not a string --> should only happen if it was a JSON object
  160. HRESULT hrJson = args->get_WebMessageAsJson(&messageRaw);
  161. if (FAILED(hrJson)) {
  162. return hrJson;
  163. }
  164. } else {
  165. return hrString;
  166. }
  167. }
  168. method_channel_->InvokeMethod(
  169. "onWebMessageReceived",
  170. std::make_unique<flutter::EncodableValue>(flutter::EncodableMap{
  171. {flutter::EncodableValue("id"), flutter::EncodableValue(web_view_id_)},
  172. {flutter::EncodableValue("message"), flutter::EncodableValue(wide_to_utf8(std::wstring(messageRaw.get())))},
  173. }));
  174. return S_OK;
  175. }
  176. ).Get(), nullptr);
  177. }
  178. void WebView::UpdateBounds() {
  179. // Resize WebView to fit the bounds of the parent window
  180. RECT bounds;
  181. GetClientRect(view_window_.get(), &bounds);
  182. webview_controller_->put_Bounds(bounds);
  183. }
  184. void WebView::Navigate(const std::wstring &url) {
  185. if (webview_) {
  186. webview_->Navigate(url.c_str());
  187. } else {
  188. std::cerr << "webview not created" << std::endl;
  189. }
  190. }
  191. void WebView::AddScriptToExecuteOnDocumentCreated(const std::wstring &javaScript) {
  192. if (webview_) {
  193. webview_->AddScriptToExecuteOnDocumentCreated(javaScript.c_str(), nullptr);
  194. }
  195. }
  196. void WebView::SetApplicationNameForUserAgent(const std::wstring &name) {
  197. if (webview_) {
  198. ICoreWebView2Settings *settings;
  199. webview_->get_Settings(&settings);
  200. ICoreWebView2Settings2 *settings2;
  201. auto hr = settings->QueryInterface(IID_PPV_ARGS(&settings2));
  202. if (SUCCEEDED(hr)) {
  203. settings2->put_UserAgent((default_user_agent_ + name).c_str());
  204. }
  205. }
  206. }
  207. void WebView::GoBack() {
  208. if (webview_) {
  209. webview_->GoBack();
  210. }
  211. }
  212. void WebView::GoForward() {
  213. if (webview_) {
  214. webview_->GoForward();
  215. }
  216. }
  217. void WebView::Reload() {
  218. if (webview_) {
  219. webview_->Reload();
  220. }
  221. }
  222. void WebView::Stop() {
  223. if (webview_) {
  224. webview_->Stop();
  225. }
  226. }
  227. void WebView::openDevToolsWindow() {
  228. if (webview_) {
  229. webview_->OpenDevToolsWindow();
  230. }
  231. }
  232. bool WebView::CanGoBack() const {
  233. if (webview_) {
  234. BOOL can_go_back;
  235. webview_->get_CanGoBack(&can_go_back);
  236. return can_go_back;
  237. }
  238. return false;
  239. }
  240. bool WebView::CanGoForward() const {
  241. if (webview_) {
  242. BOOL can_go_forward;
  243. webview_->get_CanGoForward(&can_go_forward);
  244. return can_go_forward;
  245. }
  246. return false;
  247. }
  248. void WebView::ExecuteJavaScript(const std::wstring &javaScript,
  249. std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> completer) {
  250. if (webview_) {
  251. webview_->ExecuteScript(
  252. javaScript.c_str(),
  253. Callback<ICoreWebView2ExecuteScriptCompletedHandler>(
  254. [completer(std::move(completer))](HRESULT error, PCWSTR result) -> HRESULT {
  255. if (error != S_OK) {
  256. completer->Error("0", "Error executing JavaScript");
  257. } else {
  258. completer->Success(flutter::EncodableValue(wide_to_utf8(std::wstring(result))));
  259. }
  260. return S_OK;
  261. }).Get());
  262. } else {
  263. completer->Error("0", "webview not created");
  264. }
  265. }
  266. void WebView::PostWebMessageAsString(const std::wstring &webmessage,
  267. std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> completer) {
  268. if (webview_) {
  269. if (webview_->PostWebMessageAsString(
  270. webmessage.c_str()) == NOERROR) {
  271. completer->Success();
  272. } else {
  273. completer->Error("0", "Error posting webmessage as String");
  274. }
  275. } else {
  276. completer->Error("0", "webview not created");
  277. }
  278. }
  279. void WebView::PostWebMessageAsJson(const std::wstring& webmessage,
  280. std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> completer) {
  281. if (webview_) {
  282. if (webview_->PostWebMessageAsJson(
  283. webmessage.c_str()) == NOERROR) {
  284. completer->Success();
  285. } else {
  286. completer->Error("0", "Error posting webmessage as JSON");
  287. }
  288. } else {
  289. completer->Error("0", "webview not created");
  290. }
  291. }
  292. WebView::~WebView() {
  293. if (webview_) {
  294. webview_->Stop();
  295. }
  296. if (webview_controller_) {
  297. webview_controller_->Close();
  298. }
  299. }
  300. }