feat(frontend/win): bundle webview2 installer

This commit is contained in:
liushuyu 2021-10-15 18:47:45 -06:00
parent 3196736d36
commit faba49c025
7 changed files with 75 additions and 6 deletions

2
.gitignore vendored
View file

@ -5,3 +5,5 @@
**/*.rs.bk **/*.rs.bk
*.log *.log
*.exe

2
Cargo.lock generated
View file

@ -1417,11 +1417,13 @@ dependencies = [
"slug", "slug",
"sysinfo", "sysinfo",
"tar", "tar",
"tempfile",
"tinyfiledialogs", "tinyfiledialogs",
"toml", "toml",
"url 2.2.2", "url 2.2.2",
"walkdir", "walkdir",
"webbrowser", "webbrowser",
"webview2",
"which", "which",
"widestring", "widestring",
"winapi 0.3.9", "winapi 0.3.9",

View file

@ -58,6 +58,8 @@ which = "4.0"
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["psapi", "winbase", "winioctl", "winnt"] } winapi = { version = "0.3", features = ["psapi", "winbase", "winioctl", "winnt"] }
widestring = "0.4" widestring = "0.4"
webview2 = "0.1"
tempfile = "3"
[target.'cfg(not(windows))'.dependencies] [target.'cfg(not(windows))'.dependencies]
sysinfo = "0.20" sysinfo = "0.20"

View file

@ -62,6 +62,13 @@ fn main() {
let os = OS.to_lowercase(); let os = OS.to_lowercase();
#[cfg(windows)]
{
if std::fs::metadata("MicrosoftEdgeWebview2Setup.exe").is_err() {
panic!("Please download MicrosoftEdgeWebview2Setup.exe from https://go.microsoft.com/fwlink/p/?LinkId=2124703 and put the file at the workspace root!");
}
}
// Find target config // Find target config
let target_config = PathBuf::from(format!("bootstrap.{}.toml", os)); let target_config = PathBuf::from(format!("bootstrap.{}.toml", os));

View file

@ -15,9 +15,19 @@ use wry::{
use log::Level; use log::Level;
use crate::logging::LoggingErrors;
/// Starts the main web UI. Will return when UI is closed. /// Starts the main web UI. Will return when UI is closed.
pub fn start_ui(app_name: &str, http_address: &str, is_launcher: bool) -> Result<()> { pub fn start_ui(app_name: &str, http_address: &str, is_launcher: bool) -> Result<()> {
let size = if is_launcher { (600.0, 300.0) } else { (1024.0, 600.0) }; #[cfg(windows)]
{
crate::native::prepare_install_webview2(app_name).log_expect("Unable to install webview2");
}
let size = if is_launcher {
(600.0, 300.0)
} else {
(1024.0, 600.0)
};
info!("Spawning web view instance"); info!("Spawning web view instance");
let event_loop = EventLoop::new(); let event_loop = EventLoop::new();

View file

@ -71,8 +71,8 @@ use clap::App;
use clap::Arg; use clap::Arg;
use config::BaseAttributes; use config::BaseAttributes;
use std::process::{Command, Stdio, exit};
use std::fs; use std::fs;
use std::process::{exit, Command, Stdio};
const RAW_CONFIG: &str = include_str!(concat!(env!("OUT_DIR"), "/bootstrap.toml")); const RAW_CONFIG: &str = include_str!(concat!(env!("OUT_DIR"), "/bootstrap.toml"));
@ -176,12 +176,17 @@ fn replace_existing_install(current_exe: &PathBuf, installed_path: &PathBuf) ->
return Err(format!("Unable to copy installer binary: {:?}", v)); return Err(format!("Unable to copy installer binary: {:?}", v));
} }
let existing = installed_path.join(platform_extension).into_os_string().into_string(); let existing = installed_path
.join(platform_extension)
.into_os_string()
.into_string();
let new = installed_path.join(new_tool).into_os_string().into_string(); let new = installed_path.join(new_tool).into_os_string().into_string();
if existing.is_ok() && new.is_ok() { if existing.is_ok() && new.is_ok() {
// Remove NTFS alternate stream which tells the operating system that the updater was downloaded from the internet // Remove NTFS alternate stream which tells the operating system that the updater was downloaded from the internet
if cfg!(windows) { if cfg!(windows) {
let _ = fs::remove_file(installed_path.join("maintenancetool_new.exe:Zone.Identifier:$DATA")); let _ = fs::remove_file(
installed_path.join("maintenancetool_new.exe:Zone.Identifier:$DATA"),
);
} }
info!("Launching {:?}", existing); info!("Launching {:?}", existing);
let success = Command::new(new.unwrap()) let success = Command::new(new.unwrap())

View file

@ -14,10 +14,12 @@ mod natives {
#![allow(non_snake_case)] #![allow(non_snake_case)]
const PROCESS_LEN: usize = 10192; const PROCESS_LEN: usize = 10192;
const WV2_INSTALLER_DATA: &[u8] = include_bytes!("../../MicrosoftEdgeWebview2Setup.exe");
use crate::logging::LoggingErrors; use crate::logging::LoggingErrors;
use std::env; use std::env;
use std::io::Write;
use std::os::windows::ffi::OsStrExt; use std::os::windows::ffi::OsStrExt;
use std::path::Path; use std::path::Path;
@ -34,6 +36,10 @@ mod natives {
}; };
use winapi::um::winuser::SW_SHOWDEFAULT; use winapi::um::winuser::SW_SHOWDEFAULT;
use std::process::Command;
use tempfile::Builder;
use tinyfiledialogs::{message_box_yes_no, MessageBoxIcon, YesNo};
use webview2::EnvironmentBuilder;
use widestring::U16CString; use widestring::U16CString;
extern "C" { extern "C" {
@ -56,6 +62,34 @@ mod natives {
pub fn getSystemFolder(out_path: *mut ::std::os::raw::c_ushort) -> HRESULT; pub fn getSystemFolder(out_path: *mut ::std::os::raw::c_ushort) -> HRESULT;
} }
pub fn prepare_install_webview2(name: &str) -> Result<(), String> {
if EnvironmentBuilder::default()
.get_available_browser_version_string()
.is_ok()
{
return Ok(());
}
if message_box_yes_no(&format!("{} installer", name), &format!("{} installer now requires Webview2 runtime to function properly.\nDo you wish to install it now?", name), MessageBoxIcon::Question, YesNo::Yes) == YesNo::No {
std::process::exit(1);
}
let mut installer_file = Builder::new()
.suffix(".exe")
.tempfile()
.log_expect("Unable to open the webview2 installer file");
installer_file
.write_all(&WV2_INSTALLER_DATA)
.log_expect("Unable to write the webview2 installer file");
let path = installer_file.path().to_owned();
installer_file.keep().log_unwrap();
Command::new(&path)
.arg("/install")
.spawn()
.log_expect("Unable to run the webview2 installer")
.wait()
.log_unwrap();
Ok(())
}
// Needed here for Windows interop // Needed here for Windows interop
#[allow(unsafe_code)] #[allow(unsafe_code)]
pub fn create_shortcut( pub fn create_shortcut(
@ -71,7 +105,15 @@ mod natives {
env::var("APPDATA").log_expect("APPDATA is bad, apparently"), env::var("APPDATA").log_expect("APPDATA is bad, apparently"),
name name
); );
create_shortcut_inner(source_file, name, description, target, args, working_dir, exe_path) create_shortcut_inner(
source_file,
name,
description,
target,
args,
working_dir,
exe_path,
)
} }
// Needed here for Windows interop // Needed here for Windows interop
@ -85,7 +127,6 @@ mod natives {
working_dir: &str, working_dir: &str,
exe_path: &str, exe_path: &str,
) -> Result<String, String> { ) -> Result<String, String> {
info!("Generating shortcut @ {:?}", source_file); info!("Generating shortcut @ {:?}", source_file);
let native_target_dir = U16CString::from_str(source_file.clone()) let native_target_dir = U16CString::from_str(source_file.clone())