Tauri真的是又轻又快,但由于初次使用不熟难免遇到坑。
一、虚拟键盘触摸屏之坑
ubuntu系统是一个触摸屏,不能接入键盘和鼠标,所以界面上的操作输入都是通过虚拟键盘实现。代码使用的是react-simple-keyboard 组件
import { Button } from 'antd';
import { CloseOutlined } from '@ant-design/icons';
import React, { useRef } from 'react';
import { omit } from 'lodash';
import Keyboard from 'react-simple-keyboard';
import chineseLayout from "simple-keyboard-layouts/build/layouts/chinese";
import 'react-simple-keyboard/build/css/index.css';
interface RhKeyboardProps {
    show: boolean;
    onClose: () => void;
    init?: (r: any) => void;
    onChange: (input: string) => void;
    layoutType?: string;
}
// 添加自定义布局配置
const keyboardLayout = {
    default: [
        "` 1 2 3 4 5 6 7 8 9 0 - = {bksp}",
        "{tab} q w e r t y u i o p [ ] \\",
        "{lock} a s d f g h j k l ; ' {enter}",
        "{shift} z x c v b n m , . / {shift}",
        "{space}",
    ],
    shift: [
        "~ ! @ # $ % ^ & * ( ) _ + {bksp}",
        "{tab} Q W E R T Y U I O P { } |",
        '{lock} A S D F G H J K L : " {enter}',
        "{shift} Z X C V B N M < > ? {shift}",
        "{space}",
    ],
    ...chineseLayout.layout  // 保留中文布局
};
export const RhKeyboard: React.FC<RhKeyboardProps> = ({
    show,
    onClose,
    init,
    onChange,
    layoutType,
}) => {
    const keyboardRef = useRef<any>(null);
    if (!show) return null;
    return (
        <div className="fixed bottom-0 left-0 w-full z-50 bg-gray-100"
            onTouchStart={(e) => e.stopPropagation()}
            onTouchMove={(e) => e.preventDefault()}
        >
            <div className="flex justify-end p-2">
                <Button
                    type="text"
                    icon={<CloseOutlined />}
                    onClick={onClose}
                    style={{ color: '#000' }}
                />
            </div>
            <Keyboard
                keyboardRef={(r) => {
                    (keyboardRef.current = r);
                    init?.(r);
                }}
                layout={keyboardLayout}
                {...(layoutType === 'chinese' ? omit(chineseLayout, 'layout') : {})}
                layoutName="default"
                onChange={onChange}
                useTouchEvents={true}              // 启用触摸事件支持
                // useMouseEvents={true}              // 启用鼠标事件
                disableCaretPositioning={true}     // 禁用光标定位,避免触摸冲突
                onKeyPress={(button: string) => {
                    if (button === "{shift}") {
                        const currentLayout = keyboardRef.current.options.layoutName;
                        const layoutName = currentLayout === "default" ? "shift" : "default";
                        keyboardRef.current.setOptions({ layoutName });
                    }
                }}
                theme="hg-theme-default custom-keyboard"
                buttonTheme={[
                    {
                        class: "hg-red",
                        buttons: "{shift} {lock}"
                    }
                ]}
                display={{
                    "{bksp}": "退格",
                    "{enter}": "回车",
                    "{shift}": "Shift",
                    "{space}": "空格",
                    "{tab}": "Tab",
                    "{lock}": "Lock"
                }}
            />
        </div>
    );
};
二、自动启动服务之坑
需求是开机自动启动服务并且让软件全屏,这样ubuntu的系统的盒子就像一个定制好软件的系统了。
leekhub-ui.service
[Unit]
Description=Sanyems UI Service
After=network.target
StartLimitIntervalSec=60
StartLimitBurst=3
[Service]
Environment=DISPLAY=:0
Environment=XAUTHORITY=/home/ubuntu/.Xauthority
Environment=RUST_BACKTRACE=1
ExecStartPre=/bin/bash -c 'export DISPLAY=:0; export XAUTHORITY=/home/ubuntu/.Xauthority'
ExecStart=/usr/bin/leekhub-ui
Restart=always
User=ubuntu
RestartSec=5
[Install]
WantedBy=multi-user.target
其中缺少这2行代码,脚本服务启动失败。
message: "failed to initialize gtk", filename: "/home/ubuntu/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/gtk-0.18.2/src/rt.rs", function: "gtk::rt::init", line: 141
Environment=DISPLAY=:0
Environment=XAUTHORITY=/home/ubuntu/.Xauthority
执行 sudo -u ubuntu /usr/bin/leekhub-ui 测试手动启动是否成功,注意这里的-u  指定的用户和配置文件里的User要一致,不然可能有权限问题。
权限问题则执行 sudo chown user:user /usr/bin/leekhub-ui 的方式,命令表示用户组 user,具体根据系统用户情况修改。
export DISPLAY=:0
export XAUTHORITY=/home/user/.Xauthority
source .bashrc
sudo -u user /usr/bin/leekhub-ui
如果是GTK异常,则需要安装依赖
sudo apt install libgdk-pixbuf2.0-dev libpango1.0-dev libcairo2-dev
配置文件
以下是 tauri.conf.json 代码,其中 postInstallScript 是deb包安装完成后执行的开机自动启动脚本。
{
  "$schema": "https://schema.tauri.app/config/2",
  "productName": "leekhub-ui",
  "version": "0.2.0",
  "identifier": "com.leekhub.ems",
  "mainBinaryName": "leekhub-ui",
  "build": {
    "frontendDist": "../dist",
    "devUrl": "http://localhost:3500",
    "beforeDevCommand": "pnpm dev",
    "beforeBuildCommand": "pnpm build"
  },
  "app": {
    "withGlobalTauri": true,
    "windows": [
      {
        "title": "sanyems-ui",
        "width": 1280,
        "height": 800,
        "resizable": true,
        "fullscreen": false,
        "devtools": true
      }
    ],
    "security": {
      "csp": null,
      "capabilities": [
        {
          "identifier": "custom-permision",
          "windows": [
            "*"
          ],
          "permissions": [
            "core:window:allow-create",
            "core:window:allow-close",
            "core:webview:allow-create-webview",
            "core:webview:allow-webview-close",
            "core:webview:allow-create-webview-window"
          ],
          "allowlist": {
            "http": {
              "all": true,
              "request": true,
              "scope": [
                "http://127.0.0.1:1880/ws/*",
                "http://127.0.0.1:9001/api/history/*",
                "http://127.0.0.1:9001/api/auth/*"
              ]
            },
            "protocol": {
              "asset": true,
              "assetScope": [
                "**"
              ]
            }
          }
        }
      ]
    }
  },
  "bundle": {
    "active": true,
    "targets": "all",
    "icon": [
      "icons/32x32.png",
      "icons/128x128.png",
      "icons/128x128@2x.png",
      "icons/icon.icns",
      "icons/icon.ico"
    ],
    "linux": {
      "deb": {
        "postInstallScript": "../scripts/postinstall.sh"
      }
    }
  }
}