今日は12/25クリスマスですね。
みなさん良いクリスマスをお過ごしですか?
僕はクリぼっちです、はい。
今回はクリスマスといえば雪!ということでデスクトップ上に雪を降らせてみようと思います。
使用する技術
今回はTauriを使ってみようと思います。
Tauriとは、Rustで作成されたクロスプラットフォームGUIフレームワークです。
Tauriを使うことでWindows、macOS、Linux向けのデスクトップアプリをReactなどのweb技術で書くことができます。
Tauriのセットアップ
インストール
tauriには、Bash、Powershell、npm、yarn、pnpm、deno、bun、Cargoなど多くのパッケージマネージャーを使うことができます。
今回はcargoでやってみようと思います。
create-tauri-app
cargo install create-tauri-app --locked
create-tauri-appでtaruiプロジェクトを作成します。
cargo create-tauri-app
すると諸々の設定が出てきます。
それを以下のように設定してみました。
❯ cargo create-tauri-app
✔ Project name · christmas
✔ Identifier · com.christmas.app
✔ Choose which language to use for your frontend · TypeScript / JavaScript - (pnpm, yarn, npm, deno, bun)
✔ Choose your package manager · pnpm
✔ Choose your UI template · React - (https://react.dev/)
✔ Choose your UI flavor · TypeScript
tauriのCLIツールを依存関係に追加します。
pnpm add -D @tauri-apps/cli@1
バックエンド側(Rust)
ウィンドウがマウスのイベントを透過するようにする必要があったので、Tauriのウィンドウを制御しているsrc-tauri
をいじっていこうと思います。
Tauriではtauri.conf.json
でいくつか設定を行うことができます。
設定の種類は下から探すことができます。
src-tauri
にtauri.conf.json
があるので、下のように書きました。
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "christmas",
"version": "0.1.0",
"identifier": "com.christmas.app",
"build": {
"beforeDevCommand": "pnpm dev",
"devUrl": "http://localhost:1420",
"beforeBuildCommand": "pnpm build",
"frontendDist": "../dist"
},
"app": {
"windows": [
{
"maximized": true,
"transparent": true,
"alwaysOnTop": true,
"decorations": false
}
],
"macOSPrivateApi": true,
"security": {
"csp": null
}
},
"bundle": {
"active": true,
"targets": "all",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
]
}
}
ポイントは、app
のwindows
にWindowConfigの設定を行うことがです。
この部分をいじることで画面の大きさや透明度やバーの表示などいろいろいじることができるようになります。
設定した項目としては下のようになっています。
項目 | 設定内容 |
---|---|
maximized | 画面を最大化 |
transparent | 画面を透明化 |
alwaysOnTop | 画面を再上面に |
decorations | 上部のバーを消す |
フロント側(React)
フロント側はReactで書いている関係でReactのライブラリを使うことができるので、react-snowfall
を使おうと思います。
依存関係に追加します。
pnpm add react-snowfall
このライブラリをApp.tsxで使用します。
import './App.css';
import {Snowfall} from "react-snowfall";
function App() {
const snowflake1 = document.createElement('img')
snowflake1.src = '/snowflake.png';
const image = [snowflake1]
return (
<Snowfall
color="#fff"
images={image}
style={{
position: 'fixed',
width: '100vw',
height: '100vh',
}}
radius={[5,20]}
snowflakeCount={200}
/>
)
}
export default App;
注意としては、ルートにあるpublicディレクトリに画像を入れる必要があります。
viteの仕様でpublicの置いた画像は/ファイル名
でアクセスできるようになります。
snowflakeのgithubpagesで使われている画像を持ってきました。
使用した結果
こんな感じで雪を降らせながら後ろにあるターミナル操作をできるようにしました。
ビルドしてみる
ビルドは下のコマンドで行うことができます。
pnpm tauri build
アイコンを変えてみる
デフォルトだと、ビルドしたアプリケーションのアイコンはTauriのiconになってしまいます。
アイコンを変えるには、ルートディレクトリにアイコンにしたい画像を配置して、app-icon.png
とします。
そこからtauriのicon生成コマンドがあるのでそれを打ちます。
pnpm tauri icon
すると、さまざまなサイズのアイコンがsrc-tauri/icons
の中に複製させれます。
❯ pnpm tauri icon
> christmas@0.1.0 tauri /Users/maoz/Documents/application/christmas
> tauri "icon"
Appx Creating StoreLogo.png
Appx Creating Square30x30Logo.png
Appx Creating Square44x44Logo.png
Appx Creating Square71x71Logo.png
Appx Creating Square89x89Logo.png
Appx Creating Square107x107Logo.png
Appx Creating Square142x142Logo.png
Appx Creating Square150x150Logo.png
Appx Creating Square284x284Logo.png
Appx Creating Square310x310Logo.png
ICNS Creating icon.icns
ICO Creating icon.ico
PNG Creating 32x32.png
PNG Creating 128x128.png
PNG Creating 128x128@2x.png
PNG Creating icon.png
PNG Creating mipmap-hdpi/ic_launcher_foreground.png
PNG Creating mipmap-hdpi/ic_launcher_round.png
PNG Creating mipmap-hdpi/ic_launcher.png
PNG Creating mipmap-mdpi/ic_launcher_foreground.png
PNG Creating mipmap-mdpi/ic_launcher_round.png
PNG Creating mipmap-mdpi/ic_launcher.png
PNG Creating mipmap-xhdpi/ic_launcher_foreground.png
PNG Creating mipmap-xhdpi/ic_launcher_round.png
PNG Creating mipmap-xhdpi/ic_launcher.png
PNG Creating mipmap-xxhdpi/ic_launcher_foreground.png
PNG Creating mipmap-xxhdpi/ic_launcher_round.png
PNG Creating mipmap-xxhdpi/ic_launcher.png
PNG Creating mipmap-xxxhdpi/ic_launcher_foreground.png
PNG Creating mipmap-xxxhdpi/ic_launcher_round.png
PNG Creating mipmap-xxxhdpi/ic_launcher.png
iOS Creating AppIcon-20x20@2x-1.png
iOS Creating AppIcon-20x20@1x.png
iOS Creating AppIcon-20x20@2x.png
iOS Creating AppIcon-20x20@3x.png
iOS Creating AppIcon-29x29@2x-1.png
iOS Creating AppIcon-29x29@1x.png
iOS Creating AppIcon-29x29@2x.png
iOS Creating AppIcon-29x29@3x.png
iOS Creating AppIcon-40x40@2x-1.png
iOS Creating AppIcon-40x40@1x.png
iOS Creating AppIcon-40x40@2x.png
iOS Creating AppIcon-40x40@3x.png
iOS Creating AppIcon-60x60@2x.png
iOS Creating AppIcon-60x60@3x.png
iOS Creating AppIcon-76x76@1x.png
iOS Creating AppIcon-76x76@2x.png
iOS Creating AppIcon-83.5x83.5@2x.png
iOS Creating AppIcon-512@2x.png
ここからビルドすると変更したいアプリのアイコンになります。
CIで自動ビルドさせる
GithubActionsを使って自動ビルドしてみようと思います。
.github/workflows/build.yml
に下のように記述します。
name: 'build'
on:
push:
branches:
- main
jobs:
publish-tauri:
permissions:
contents: write
strategy:
fail-fast: false
matrix:
include:
- platform: 'macos-latest' # for Arm based macs (M1 and above).
args: '--target aarch64-apple-darwin'
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
- name: setup node
uses: actions/setup-node@v4
with:
node-version: lts/*
- name: setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
- name: install frontend dependencies
run: pnpm install
- uses: tauri-apps/tauri-action@v0.5.18
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tagName: app-v__VERSION__
releaseName: 'App v__VERSION__'
releaseBody: 'See the assets to download this version and install.'
releaseDraft: false
prerelease: false
args: ${{ matrix.args }}
mainブランチにpush(or PRでマージされた時)にactionsが走るようにしています。
またmatrixを使うことでos毎にビルドの仕方を変えるようにしています。
stepsで行ってることは以下の通りです。
step | 内容 |
---|---|
actions/checkout@v4 | actions内にリポジトリをクローンしています |
actions/setup-node@v4 | actions内にnodeをセットアップしています |
pnpm/action-setup@v4 | pnpmをセットアップしています |
dtolnay/rust-toolchain@stable | 安定ver(stable)のrustの環境をセットアップしています。 |
pnpm install | pnpmで依存関係をインストールしています |
tauri-apps/tauri-action@v0.5.18 | 自動ビルドとreleaseに自動的にあげるようにしています |
これでmainにpushされるとreleasesページに作成されます。
これはおそらくですが、公証というアプリケーションに対して安全であるという署名がないからだと考えられます。
なのでxattrコマンドで許可する必要があります。
自己責任でお願いします
xattr -rc /Applicaions/christmas.app
おまけ
setIgnoreMouseEventのやり方を調べる過程でしたのissueを参考にしようとしました。
しかし、ここに書いてあるのは2年前の文法でTauriはv2.0で変わったばっかりでここに書かれているコードでは動かすことができませんでした。
その際にGPTとかドキュメントとかを読んで動いたコードは下のようになりました。
use tauri::Manager;
#[cfg(target_os = "macos")]
use cocoa::appkit::NSWindow;
pub fn run() {
tauri::Builder::default()
.setup(|app| {
let window = app.get_webview_window("main").unwrap();
#[cfg(target_os = "macos")]
unsafe {
let ns_window = window.ns_window().unwrap() as cocoa::base::id;
// マウスイベントを透過させる
ns_window.setIgnoresMouseEvents_(cocoa::base::YES);
}
window.set_always_on_top(true)?;
window.set_decorations(false)?;
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
use cocoa::appkit::NSWindow
は、macOSのアプリケーションで使われるappKitのNSWindowクラスを呼び出しています。
TauriはRustでOSのAPIを叩くことができます。それを利用して上記のようにAPIを無理やり叩いていました。
ただ、ver2.0から標準設定ができるようになりよしなに叩くAPIを切り替えたりしてくれるようになったぽいです。
さすがTauriですね。
リポジトリ
リポジトリは下にあります。
よかったらクローンして遊んでみてください!