由于自己最近在健身(减肥)嘛,教练告诉一定要多喝水,但是由于从小就没有勤喝水的习惯,导致自己还是经常忘了要喝水,总是渴的不行的时候才想起来喝...
正好之前见到过不少提醒喝水的软件,尝试使用了一波,发现并不是很符合自己的需求,原因有以下几点:
1、好看的大都在手机上,我不希望用手机来提醒,因为平时敲代码并不会看手机,如果震动或者声音,太影响其他人。
2、电脑上的也有,但是提醒的强度不高,都是通过“通知”来进行,强度太小了,存在感太低,我需要一个强提醒,最好是弹到脸上的那种。
3、自己也想试试开发一款桌面APP...
基于以上的一些原因吧,在空余时间,尝试了一把桌面APP的开发,期间的一些思考和了解在下面简单做了一下记录。
技术选型
“工欲善其事,必先利其器”,开始前,首先要想想自己要使用什么顺手的工具...
因为自己首先想的是给自己用,平时Mac占据100%的场景,所以首先想到的是原生开发
1、Objective-C or Swift UI
// Objective-C
@implementation Person @synthesize name;
- (id)initWithAge:(int)initAge {
self = [super init];
if (self) {
// NOTE: direct instance variable assignment, not property setter age = initAge;
}
return self;
}
- (int)age {
return age;
}
@end
// Swift UI
extension Player {
mutating func updateScore(_ newScore: Int) {
history.append(newScore)
if highScore < newScore {
print("(newScore)! A new high score for (name)! 🎉")
highScore = newScore
}
}
}
player.updateScore(50)
简单看了一下,OC的语法写起来相当复杂,学习成本相当高,Swift UI看起来和JS差不太多,不过也有很多语法不一致,并且需要学习很多的原生知识、更换编辑器等等...
总体看,使用原生语言来开发的话,学习成本还是相当高的,为了开发一个小APP,ROI太小了,果断放弃。
2、Electron
这时候,忽然想起之前有简单了解过Electron,前段时间分享的《浅浅析B站桌面端主题色切换效果》中的B站的桌面软件,就是基于Electron来开发的。
Electron是使用JavaScript,HTML和CSS构建跨平台的桌面应用程序框架。 Electron兼容Mac、Windows和Linux,可以构建出三个平台的应用程序。
其有一个非常吸引人的点是:可以使用JS+HTML+CSS来进行页面布局,如果你是一个前端开发er,你可以几乎无门槛上手electron,并且它的官方文档写的很详细,很快就可以搞出来一个可用的桌面app,并且可以打出来多个平台的安装包(如果你需要的话)。
(图片来自https://baijiahao.baidu.com/s?id=1744722241805764527&wfr=spider&for=pc)
毫无疑问,这是一个对我来说相当完美的方案,就它了!
基于Electron的APP架构图
页面效果
1、安装页
2、提示页
3、数据页
4、设置页
5、顶部托盘展示
6、演示gif
期望的效果也都达到了:
-
重提示(弹到脸上)
-
方便操作(功能简单)
-
还算可以入眼
-
可以统计历史数据
本可以至此就完美结束,但是在打包之后,其安装包大小犹如一块石头一样压在我心里,实在是接受不了这么一个小玩意儿要那么大的体积...
226M... 实在是超出预期太多太多了...
就像这种小功能,我最多能接受的大小就是20M以内
再多就实在是接受不了了
通过一些了解,可以通过调整dependencies与devDependencies内的依赖的位置,将页面需要的依赖都挪到dev下,这样让体积减小了大概30M左右,但是最终的体积还是比较大,比较愁人...
在寻找优化体积的过程中发现了tauri这样一个库,其官方介绍:
发现其有一点深得我心,即:使用系统自带的网页渲染器,其应用的打包体积可以倒 600KB 以下!
和electron对比一下
Tauri App体积非常小,因为它使用操作系统的 webview。它不提供运行时,因为最终的二进制文件是从 Rust 编译的。这使得 Tauri 应用程序的逆向不是一项简单的任务(得亏B站没用这个来编写,不然上次的分享可就做不了了😂)。
可以看到,其中比较难搞就是主进程的代码是使用Rust来开发的,之前没有写过Rust,纠结了好长一段时间。
最后还是决定试一试,大概有下面两点原因吧:
1、前端基建目前在朝go、rust构建发展,比如esbuild(go),Deno(rust),SWC(rust)等等
2、尝试多了解一门语言,为以后创造更多实现场景
基于Tauri的APP架构图
主要做了定时器、主进程store、主进程和UI进程之间通讯方式的调整
一些主要代码
// main.rs
#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
// 引入依赖
use tauri::{Manager, Size};
use tauri::{PhysicalSize, SystemTray, SystemTrayEvent};
// 激活页面,从react中触发展示
#[tauri::command]
fn active_window(app_handle: tauri::AppHandle) {
let main_window = app_handle.get_window("main").unwrap();
main_window.show().unwrap();
main_window.emit("active_window", "").expect("事件触发异常");
main_window.set_focus().unwrap();
}
// 更新托盘中的的title展示
#[tauri::command]
fn update_tray_title(app_handle: tauri::AppHandle, count: &str) {
app_handle
.tray_handle()
.set_title(&format!("别忘了饮水!今日已饮 {} 次", count).to_string()[..])
.expect("title设置异常")
}
fn main() {
tauri::Builder::default()
.setup(|app| {
// 设置激活策略
// 每次激活时,都在当前页面展示窗口
#[cfg(target_os = "macos")]
app.set_activation_policy(tauri::ActivationPolicy::Accessory);
// 设置窗口的大小为显示器大小
let main_window = app.get_window("main").unwrap();
let current_monitor = main_window.current_monitor().unwrap();
let current_monitor_unwrap = current_monitor.unwrap();
let size = current_monitor_unwrap.size();
main_window
.set_size(Size::Physical(PhysicalSize {
width: size.width,
height: size.height + 100,
}))
.unwrap();
// 设置展示在最上层
main_window.set_always_on_top(true).unwrap();
// 打开dev_tools
// main_window.open_devtools();
Ok(())
})
.system_tray(SystemTray::new())
.on_system_tray_event(move |app, event| match event {
SystemTrayEvent::LeftClick {
position: _,
size: _,
..
} => {
// 点击托盘事件回调
let main_window = app.get_window("main").unwrap();
// 派发事件,展示window
main_window
.emit("tray_show_window", "")
.expect("事件触发异常");
}
_ => {}
})
.on_window_event(|event| match event.event() {
tauri::WindowEvent::CloseRequested { api, .. } => {
// 当点击关闭按钮时,不退出程序
// 这里暂时没有使用,因为顶部操作按钮都给隐藏了
event.window().hide().unwrap();
api.prevent_close();
}
tauri::WindowEvent::Focused(false) => {}
_ => {}
})
// 注册事件(供react中调用的方法)
.invoke_handler(tauri::generate_handler![active_window, update_tray_title])
// 执行
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
// 在js中调用rust方法
import { invoke } from "@tauri-apps/api";
invoke("active_window");
这里就可以通过tauri提供的包来从js调用rust中的代码,猜测原理和js-bridge差不多,rust往window上注入对象,调用invoke的时候,其实是执行window对象上的方法(猜测,还没有去确认)。
值得注意的:
tauri目前来看还没有electron的社区活跃,一些功能还是缺失的,比如我想做的开机自启动、dock栏事件监听,目前官方还是没有支持的。
不过用它来支持一些小工具开发是非常合适的,如果是做公司业务的技术选型,需要做更深层次的调研才可以。
反馈
以上就是实现这个小桌面APP的主要经过,目前它正很符合预期的运行在我的电脑中。
今天我也比平时多喝了三杯水,嗯,还是有用的hhh!
参考地址
下载地址
安装包程序:bj-mutou-1301404888.cos.ap-beijing.myqcloud.com/water-water…