【tauri开发】windows管理员身份开机启动

2024-06-25 15:17:08 浏览数 (1)

前言

最近遇到个bug,问题一路捋上来,查到了windows权限相关,即我需要将应用改成默认使用管理员身份运行

我看了看代码,试了一下,果然tauri自带的开机启动插件[1]没能在开机时打开默认管理员权限运行的软件

经过一番搜索,找到了windows下有个名为Task Scheduler[2](任务计划程序)的东西,可以在用户登录时执行一个动作

既然可行,那说做就做

默认管理员身份

先把应用改成默认管理员身份,查了一下tauri相关issue[3],在build.rs按以下修改即可

代码语言:javascript复制
代码语言:javascript复制
let mut windows = tauri_build::WindowsAttributes::new();
windows = windows.app_manifest(r#"
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        processorArchitecture="*"
        publicKeyToken="6595b64144ccf1df"
        language="*"
      />
    </dependentAssembly>
  </dependency>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
        <requestedPrivileges>
            <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
        </requestedPrivileges>
    </security>
  </trustInfo>
</assembly>
"#);
tauri_build::try_build(
  tauri_build::Attributes::new().windows_attributes(windows)
).expect("failed to run build script");

到rust仓库找了一圈,找到了 windows task scheduler API的封装planif[4],看了看案例,由于对 task scheduler完全不了解,花了一段时间摸索

关于使用planif实现开机自启动,具体见此处[5]

把引用和一些无关内容去除,大致见下面

懂rust的人会觉得代码有点奇怪,但下面我就要讲踩到的坑

代码语言:javascript复制
fn spawn_autostart(enabled: bool) -> Result<()> {
    let (tx, rx) = mpsc::channel();

    thread::spawn(move || {
        let _ = tx.send(autostart(enabled).map_err(|e| anyhow!(e.to_string())));
    });

    Ok(rx.recv().map_err(|e| anyhow!(e))??)
}

fn autostart(enabled: bool) -> std::result::Result<(), Box<dyn std::error::Error>> {
    let ts = TaskScheduler::new()?;
    let com = ts.get_com();
    let sb = ScheduleBuilder::new(&com).unwrap();

    let exe = current_exe()?;
    let exe = exe.to_str().unwrap();

    let settings = PrincipalSettings {
        display_name: "".to_string(),
        group_id: None,
        id: "".to_string(),
        logon_type: LogonType::InteractiveToken,
        run_level: RunLevel::Highest,
        user_id: Some(whoami::username()),
    };

    sb.create_logon()
        .author("hanaTsuk1")?
        .trigger("trigger", enabled)?
        .action(Action::new("auto start", exe, "", ""))?
        .in_folder("shion")?
        .principal(settings)?
        .delay(Duration {
            seconds: Some(6),
            ..Default::default()
        })?
        .build()?
        .register("auto start", TaskCreationFlags::CreateOrUpdate as i32)?;
    Ok(())
}

pub fn enable() -> Result<()> {
    spawn_autostart(true)
}

pub fn disable() -> Result<()> {
    spawn_autostart(false)
}

创建任务

在创建任务时,单独测试非常正常。但一放到tauri里运行,就会报错

无法在设置线程模式后对其加以更改。 (0x80010106)

经过一番搜索,找到错误与CoInitializeEx[6]有关,它的线程模式存在COINIT_APARTMENTTHREADEDCOINIT_MULTITHREADED两种,我使用的库planif和tauri都调用了CoInitializeEx,但选择的模式不同,于是报错

tauri官方给出的解决方案是issue[7],即开一个新线程调用CoInitializeEx

托盘消失

在成功创建完任务后,我尝试了重启看看效果,但非常奇怪并没有生效,于是我尝试了几次发现

程序的确运行了,但托盘有时存在,有时又不存在

我以为是tauri的问题,于是查了半天无果,但仔细一想平时托盘都不会出现这样的问题。会不会是开机启动时系统还没准备好,程序就运行了,于是我打开任务计划程序

发现我的程序上次运行时间总是比其他的软件要早

mmc_HSMrpjIz4O.png

于是找了找延迟相关的代码

延迟失效

我设置了延迟,但发现还是一样没有变化,折腾一圈,发现和planif[8]仓库最近的提交有关系

即作者改了bug,但crate最新版还没有改,于是把源指向github仓库

大功告成

总结

从一个坑爬出来又掉到另一个,但好歹实现了 说一下planif相关的代码

代码语言:javascript复制
代码语言:javascript复制
run_level: RunLevel::Highest  // 设置管理员权限

sb.create_logon()  // 创建一个用户登录后执行的动作

.trigger("trigger", enabled)?  // 通过控制enabled值来实现启用或禁用

.action(Action::new("auto start", exe, "", ""))?  // action就是要运行的软件

.in_folder("shion")?  // 看到上面那张图了吗?它会在左侧创建一个文件夹

// 名称,然后创建并更新
.register("auto start", TaskCreationFlags::CreateOrUpdate as i32)?;

更新

运行生效,正当我准备打包测试时,问题接踵而至

tauri nsis更新会下载setup程序,我在本地运行测试,发现setup程序更新完自行启动后软件却没有启动

setup是普通用户身份,包含的软件是管理员身份,是这个原因吗?

查了一下tauri的配置[9],将installMode设置为both,即可让setup程序默认以管理员身份运行

试了一下,成功


上传代码,一键github action启动,接下来便是等待release生成,然后测试真实打包情况了

不出意外的话,接下来就要出意外了

0 人点赞