1. 唠嗑

主机测评目前主要用的都是苹果生态的设备,登录了同一个Apple账号之后,是可以实现电脑复制,手机粘贴内容的,反之亦然。相信安卓也有类似的功能。

但是仍有不少小伙伴是安卓和苹果混用的,甚至是windows和Linux混用的,有没有一个方案可以也实现跨设备之间也粘贴同步呢?

今天介绍的SyncClipboard就是要实现这个功能的,感谢@chin的推荐。

十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目

2. SyncClipboard主要功能(来自官方GitHub

  • 剪贴板同步,支持文字、图片和文件。服务器/客户端架构,可以使用客户端内置服务器、独立部署服务器,也可以使用支持WebDAV的网盘作为服务器
  • 优化图片类型的剪贴板,功能有:
    • 从任意位置复制图片时,可以直接向文件系统粘贴图片文件,反之亦然
    • 从浏览器复制图片后,后台下载原图到本地,解决无法从浏览器拷贝动态图的问题(大多网站有认证,适用范围有限,支持bilibili动态图片)
    • 从文件系统复制较新格式类型的图片文件时(webp/heic等),在剪贴板内储存gif或jpg格式,用于直接向支持图片的文本框粘贴图片

3. 相关地址

官方GitHub地址:https://github.com/Jeric-X/SyncClipboard (全新项目,目前1.9个star,欢迎大家去给项目点星星!)

4. 搭建环境

当然你也可以选择不自己搭服务器用客户端内置服务器(可能有小伙伴担心隐私问题),或者是WebDAV服务器。

可以使用支持WebDAV协议的网盘作为服务器
测试过的服务器:

5. 搭建视频(过俩天补充 = =)

5.1 YouTube

视频地址:

5.2 哔哩哔哩

哔哩哔哩:

6. 搭建方式

6.1 安装 Docker 与 Nginx Proxy Manager

可以直接参考这篇内容:

https://blog.laoda.de/archives/nginxproxymanager/

6.2 创建安装目录

创建一下安装的目录:

sudo -i  mkdir -p /root/data/docker_data/syncclipboard  cd /root/data/docker_data/syncclipboard 

接着我们来编辑下docker-compose.yml

vim docker-compose.yml 
services:   syncclipboard-server:     image: jericx/syncclipboard-server:latest     container_name: syncclipboard-server     restart: unless-stopped     ports:       - "5133:5033" # 左边的5133可以改成服务器上没有用过的其他端口     environment:       - SYNCCLIPBOARD_USERNAME=这里改成你的英文的用户名       - SYNCCLIPBOARD_PASSWORD=这个改成你的密码 

其中的5133可以改成服务器上没有用过的端口,记得修改自己的用户名和密码,修改完成之后,可以在英文输入法下,按 i 修改,完成之后,按一下 esc,然后 :wq 保存退出。

6.3 查看端口是否被占用

查看端口是否被占用(以 5133 为例),输入:

lsof -i:5133  #查看 5133 端口是否被占用,如果被占用,重新自定义一个端口 

如果啥也没出现,表示端口未被占用,我们可以继续下面的操作了~

如果出现:

-bash: lsof: command not found 

运行:

apt install lsof  #安装 lsof 

如果端口没有被占用(被占用了就修改一下端口,比如改成 8381,注意 docker 命令行里和防火墙都要改)

6.4 启动 syncclipboard

cd /root/data/docker_data/syncclipboard  docker compose up -d   # 注意,老版本用户用 docker-compose up -d 

耐心等待拉取好镜像,出现 done的字样之后,

理论上我们就可以输入 http://ip:5133 访问了。

但是这边这个服务必须先搞一下反向代理!http使用明文传输太危险,我们部署在公网一定要考虑使用反向代理工具配置SSL!

做反向代理前,你需要一个域名!

namesilo 上面 xyz 后缀的域名一年就 7 块钱,可以年抛。(冷知识,namesilo上 6位数字的xyz续费永远都是0.99美元 = =)

如果想要长期使用,还是建议买 com 后缀的域名,更加正规一些,可以输入 laodade 来获得 1 美元的优惠(不知道现在还有没有)

namesilo 自带隐私保护,主机测评一直在用这家,价格也是这些注册商里面比较低的,关键是他家不像其他家域名注册商,没有七七八八的套路!(就是后台界面有些 古老 = =)

【域名购买】Namesilo 优惠码和域名解析教程(附带服务器购买推荐和注意事项)

我们接着往下看!

7. 反向代理

7.1 利用 Nginx Proxy Manager

在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上域名购买、域名解析 视频教程) (名称改成你自己想要的域名前缀即可)

十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目

之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager相关教程))

注意:

Nginx Proxy Manager(以下简称 NPM)会用到 80443 端口,所以本机不能占用(比如原来就有 Nginx)

直接丢几张图:

十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目 十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目 十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目 十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目

注意填写对应的 域名IP端口,按文章来的话,应该是 5133

IP 填写:

如果 Nginx Proxy Manager 和 SyncClipboard 在同一台服务器上,可以在终端输入:

ip addr show docker0 

查看对应的 Docker 容器内部 IP。

十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目

否则直接填 syncclipboard 所在的服务器 IP 就行。

7.2 利用宝塔面板

发现还是有不少小伙伴习惯用宝塔面板,这边也贴一个宝塔面板的反代配置:

直接新建一个站点,不要数据库,不要 php,纯静态即可。

然后打开下面的配置,修改 Nginx 的配置。

十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目 十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目

代码如下:

location / {       proxy_pass http://127.0.0.1:5133/;       # 注意改成你实际使用的端口       rewrite ^/(.*)$ /$1 break;       proxy_redirect off;       proxy_set_header Host $host;       proxy_set_header X-Forwarded-Proto $scheme;       proxy_set_header X-Real-IP $remote_addr;       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;       proxy_set_header Upgrade-Insecure-Requests 1;       proxy_set_header X-Forwarded-Proto https;     } 

此方法对 90% 的反向代理都能生效,然后就可以用域名来安装访问了。

有同学可能会问,为什么不直接用宝塔自带的反向代理功能。

十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目

也可以,不过主机测评自己之前遇到过当有多个网站需要反代的时候,在这边设置会报错的情况 = =

所以后来就不用了,直接用上面的方法来操作了。

8. 使用教程

8.1 登陆使用(以安卓和IOS为例子)

这边我手头没有window电脑,我演示一下安卓和IOS如何互通粘贴板。

安卓配置

安卓下载一个APP——HTTP Request Shortcuts

十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目

可以直接在谷歌应用商店搜索下载:https://play.google.com/store/apps/details?id=ch.rmy.android.http_shortcuts

也可以在F-Droid下载:https://f-droid.org/en/packages/ch.rmy.android.http_shortcuts/

或者直接GitHub上下载:https://github.com/Waboodoo/HTTP-Shortcuts/releases

HTTP Request Shortcuts的GitHub仓库:https://github.com/Waboodoo/HTTP-Shortcuts

手机上下载,导入这个配置文件

这个是个压缩包,解压之后是个json文件,然后一会儿上传到HTTP Request Shortcuts里面即可。

json的内容是这个:

{   "categories": [     {       "id": "accb6a5b-60a3-4ba5-921a-f9cd772067aa",       "name": "快捷方式",       "shortcuts": [         {           "authentication": "basic",           "bodyContent": "{"File":"","Clipboard":"{{76b1e948-84b3-497e-8ec5-b911d00f8f0f}}","Type":"Text"}",           "codeOnSuccess": "showToast(u0027已上传u0027);",           "contentType": "application/json",           "description": "支持选中文字后分享",           "iconName": "freepik_upload",           "id": "d6a958cb-3fa6-4c79-b342-229008bfac8a",           "method": "PUT",           "name": "上传剪贴板",           "password": "{{9421719b-086f-4799-8432-158b84b6e05a}}",           "proxy": "",           "quickSettingsTileShortcut": true,           "responseHandling": {             "successOutput": "none"           },           "url": "{{136751b5-5f38-49fc-81dc-80a825804203}}/SyncClipboard.json",           "username": "{{719f997c-6bf6-458f-a148-3c2a8ac5e405}}"         },         {           "authentication": "basic",           "codeOnSuccess": "const profile u003d JSON.parse(response.body)rnconst type u003d profile.Typernrnif (type u003du003d u0027Textu0027) {rn    const ClibboardText u003d profile.Clipboard;rn    copyToClipboard(ClibboardText);rn    showToast(u0027已拷贝\nu0027 + ClibboardText);rnrn    const httpstr u003d httpString(ClibboardText);rnrn    if (httpstr) {rn        if (confirm(u0027包含网址,是否打开u0027)) {rn            openUrl(httpstr[0]);rn        }rn    }rn}rnelse if (profile.File u0026u0026 profile.File.length u003e 0) {rn    const downloadUrl u003d getVariable(/*[variable]*/"136751b5-5f38-49fc-81dc-80a825804203"/*[/variable]*/) + u0027/file/u0027 + encodeURIComponent(profile.File)rn    const inputPara u003d { u0027downloadUrlu0027: downloadUrl }rn    showToast(u0027文件名已拷贝,正在下载\nu0027 + profile.File)rn    copyToClipboard(profile.File)rn    if (type u003du003d u0027Imageu0027 || isImageFile(profile.File)) {rn        enqueueShortcut(/*[shortcut]*/"1e693964-ab59-4e9c-902b-6b94b90ff2f0"/*[/shortcut]*/, inputPara)rn    } else {rn        enqueueShortcut(/*[shortcut]*/"1e693964-ab59-4e9c-902b-6b94b90ff2f0"/*[/shortcut]*/, inputPara)rn    }rn}rnrnfunction isImageFile(file) {rn    const filename u003d file.toLowerCase();rn    const list u003d [rn        u0027.pngu0027,rn        u0027.jpgu0027,rn        u0027.jpegu0027,rn        u0027.gifu0027,rn        u0027.bmpu0027,rn        u0027.webpu0027,rn    ]rn    let result u003d falsern    list.forEach(element u003du003e {rn        if (filename.endsWith(element)) {rn            result u003d truern        }rn    })rn    return resultrn}rnrnfunction httpString(s) {rn    var reg u003d /(https?|http|ftp|file):\/\/[-A-Za-z0-9+u0026@#/%?u003d~_|!:,.;]+[-A-Za-z0-9+u0026@#/%u003d~_|]/g;rn    s u003d s.match(reg);rn    return (s)rn}",           "iconName": "freepik_download",           "id": "91cf41c5-da0c-45b5-988c-9f636e135abd",           "name": "下载剪贴板",           "password": "{{9421719b-086f-4799-8432-158b84b6e05a}}",           "proxy": "",           "quickSettingsTileShortcut": true,           "responseHandling": {             "successOutput": "none"           },           "url": "{{136751b5-5f38-49fc-81dc-80a825804203}}/SyncClipboard.json",           "username": "{{719f997c-6bf6-458f-a148-3c2a8ac5e405}}"         },         {           "authentication": "basic",           "bodyContent": "{"File":"","Clipboard":"{{76b1e948-84b3-497e-8ec5-b911d00f8f0f}}","Type":"Text"}",           "codeOnPrepare": "setVariable(/*[variable]*/"d12cab01-6d2b-44aa-a1fb-dfddc6fe7895"/*[/variable]*/, selectedFiles[0].name);",           "codeOnSuccess": "enqueueShortcut(u0027上传文件 控制部分u0027)",           "contentType": "application/json",           "description": "从分享菜单使用",           "iconName": "freepik_upload",           "id": "2b8e95a4-2ece-41a1-aace-f8f80c0497fb",           "method": "PUT",           "name": "上传文件",           "password": "{{9421719b-086f-4799-8432-158b84b6e05a}}",           "proxy": "",           "requestBodyType": "file",           "responseHandling": {             "successOutput": "none"           },           "url": "{{136751b5-5f38-49fc-81dc-80a825804203}}/file/{{d12cab01-6d2b-44aa-a1fb-dfddc6fe7895}}",           "username": "{{719f997c-6bf6-458f-a148-3c2a8ac5e405}}"         }       ]     },     {       "id": "316553f3-4bb0-4e10-806b-0de26e10fb2a",       "name": "基础组件",       "shortcutClickBehavior": "edit",       "shortcuts": [         {           "authentication": "basic",           "bodyContent": "{"File":"{{d12cab01-6d2b-44aa-a1fb-dfddc6fe7895}}","Clipboard":"","Type":"File"}",           "codeOnSuccess": "showToast(u0027已上传u0027);",           "contentType": "application/json",           "iconName": "freepik_upload",           "id": "2424dcac-6fa0-4ff9-849b-63a56d63c79f",           "method": "PUT",           "name": "上传文件 控制部分",           "password": "{{9421719b-086f-4799-8432-158b84b6e05a}}",           "proxy": "",           "responseHandling": {             "successOutput": "none"           },           "url": "{{136751b5-5f38-49fc-81dc-80a825804203}}/SyncClipboard.json",           "username": "{{719f997c-6bf6-458f-a148-3c2a8ac5e405}}"         },         {           "authentication": "basic",           "bodyContent": "{"File":"","Clipboard":"{{76b1e948-84b3-497e-8ec5-b911d00f8f0f}}","Type":"Text"}",           "contentType": "application/json",           "description": "只支持2m以下文件",           "iconName": "flat_color_folder",           "id": "1e693964-ab59-4e9c-902b-6b94b90ff2f0",           "name": "展示文件",           "password": "{{9421719b-086f-4799-8432-158b84b6e05a}}",           "proxy": "",           "requestBodyType": "file",           "responseHandling": {             "actions": [               "share",               "copy",               "save"             ]           },           "url": "{{5989c421-2669-4424-80c3-69ba7995524a}}",           "username": "{{719f997c-6bf6-458f-a148-3c2a8ac5e405}}"         }       ]     }   ],   "compatibilityVersion": 71,   "variables": [     {       "id": "719f997c-6bf6-458f-a148-3c2a8ac5e405",       "key": "UserName",       "value": "ChangeIt"     },     {       "id": "9421719b-086f-4799-8432-158b84b6e05a",       "key": "UserToken",       "value": "ChangeIt"     },     {       "flags": 1,       "id": "76b1e948-84b3-497e-8ec5-b911d00f8f0f",       "jsonEncode": true,       "key": "Clipboard",       "type": "clipboard"     },     {       "id": "d12cab01-6d2b-44aa-a1fb-dfddc6fe7895",       "jsonEncode": true,       "key": "FileName",       "value": ""     },     {       "id": "136751b5-5f38-49fc-81dc-80a825804203",       "key": "url",       "value": "ChangeIt"     },     {       "id": "5989c421-2669-4424-80c3-69ba7995524a",       "key": "downloadUrl",       "value": ""     }   ],   "version": 75 } 

十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目 十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目 十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目

修改变量中的UserNameUserTokenurlurl不要以斜线分隔符/结尾。

十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目 十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目 十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目 十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目 十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目

HTTP Request Shortcuts支持从下拉菜单、桌面组件、桌面图标、分享菜单中使用。

IOS配置

官方给了很多选择:

使用快捷指令

  • 手动同步,导入这个快捷指令,手动触发上传或下载
  • 自动同步,导入这个快捷指令,运行后设备会自动在后台同步剪贴板内容,此快捷指令将执行无限时长,需要手动关闭,你还可以手动修改同步后是否发送系统通知、查询的间隔秒数
  • 自动上传短信验证码,参考这个帖子中的视频教程 #60

我自己偏向于手动同步,所以导入了这个快捷指令,手动触发上传或下载。

十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目

记得修改一下这三个,

十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目

然后保持就可以了。

试试效果吧!亲测非常好用!

WIndows, Linux, macOS客户端,Arch Linux还有其他安卓的方式,大家可以参考官方的文档:https://github.com/Jeric-X/SyncClipboard

为了避免有些小伙伴访问不了,我也粘贴一份在博客里:

桌面客户端(Windows/Linux/macOS)运行在后台时将自动同步剪贴板

Windows

下载地址:Release页面中的SyncClipboard.zip,解压缩后运行SyncClipboard.exe

依赖:

注意:

  • 删除软件时,配置文件目录不会被删除,配置文件储存在%AppData%SyncClipboard,需要彻底删除软件时请手动删除整个目录

Linux, macOS

下载地址:SyncClipboard.Desktop,根据系统选择你需要的安装包

注意:

  • 名称中带有no-self-contained:依赖.NET 6.0桌面运行时ASP.NET Core 6.0运行时
  • 名称中带有self-contained:通常可以直接运行
  • 删除软件时,配置文件目录不会被删除,配置文件储存在~/.config/SyncClipboard/(Linux),~/Library/Application Support/SyncClipboard/(macOS),需要彻底删除软件时请手动删除整个目录
  • 使用debrpm安装包时,每次更新版本需要先删除旧版,再安装新版,不支持直接更新
  • Linux: 快捷键在Wayland不可用
  • Linux: 无法自动识别语言,默认为英语
  • macOS: “SyncClipboard”已损坏,无法打开,在终端中执行sudo xattr -d com.apple.quarantine /Applications/SyncClipboard.app
  • macOS: 快捷键依赖辅助功能权限(Accessibility),软件在需要时会弹窗提示(所有快捷键为空时则不需要),每个新版本需要重新授予权限

Arch Linux

Arch Linux 用户可以直接从 AUR 安装:

paru -Sy syncclipboard-desktop 

安装后从菜单中启动即可,如果要从命令行中启动,请注意需要英文环境,即以 LANG=en_US.UTF-8 syncclipboard-desktop 来启动,启动后可以在软件内设置语言为中文。配置保存路径为:~/.config/SyncClipboard

Android

使用HTTP Request Shortcuts

导入这个配置文件,修改变量中的UserNameUserTokenurlurl不要以斜线分隔符/结尾。HTTP Request Shortcuts支持从下拉菜单、桌面组件、桌面图标、分享菜单中使用

使用Autox.js
  • 自动同步,使用这个js文件。由于安卓系统限制,在安卓10及以上的系统应用无法在后台读取剪贴板,但可以使用基于Root权限的工具(Magisk/Xposed)解除应用后台读取剪贴版的权限,如Riru-ClipboardWhitelistClipboard Whitelist。由于在安卓13及以上的系统应用必须由用户手动授权才被允许访问系统日志(剪贴板),也可以使用Xposed自动为应用授权访问系统日志的权限,如DisableLogRequest/禁用日志访问请求
  • 自动上传验证码,使用这个js文件,这个脚本运行在后台时将读取所有通知消息,在识别到验证码类信息时将证码上传到服务器

导入js文件、修改每个文件头部的用户配置后,手动点击运行,或者为每个js文件设置触发方式,例如:开机时触发

使用SmsForwarder
  • 自动上传验证码, #109
使用Tasker
  • https://github.com/forrestgao/taskerforSyncClipboard ,作者:forrestgao

Tasker是一款安卓系统上非常强大的自动化工具软件,你可以根据SyncClipboard的API创建适合自己的配置文件,如果你认为你的配置文件非常通用并希望分享出来,欢迎联系我置于此处

客户端配置说明

全平台依赖三条必要配置(配置的拼写可能会有所不同,含义相同)。

  • user
  • password
  • url,格式为http(s)://ip(或者域名):port。使用WebDav服务器时,url需要具体到一个已存在的文件夹作为工作目录,例如https://domain.com/dav/folder1/working%20folder,特殊符号需要使用url转义字符代替,不要使用这个文件夹存储其他文件。不使用桌面客户端(Windows/Linux/macOS)时需在工作目录中再创建file文件夹以同步文件,桌面客户端会在设置服务器时自动创建file文件夹。url尽量不要以斜线分隔符/结尾,在部分客户端中会出现问题。

API

API基于WebDAV,在独立服务器运行环境下设定环境变量ASPNETCORE_ENVIRONMENT为Development后运行服务器,或桌面客户端打开服务器并打开设置里的诊断模式后, 访问http://ip:端口/swagger/index.html可以打开API页面,以下是部分关键API

获取/上传剪贴板(文字)

GET /SyncClipboard.json PUT /SyncClipboard.json 

获取/上传剪贴板(图片/文件)

GET  /SyncClipboard.json HEAD /file/filename         // optional GET  /file/filename  PUT /file/filename PUT /SyncClipboard.json 

SyncClipboard.json

{     "Type" : "Text"     "Clipboard" : "Content",     "File":"" }  {     "Type": "Image", // or "File", "Group"     "Clipboard": "hash, optional",     "File": "filename" } 

8.2 更新 SyncClipboard

这个项目后续应该也会有更新,所以提供一个更新的方式。

cd /root/data/docker_data/syncclipboard  docker compose pull  docker compose up -d    # 请不要使用 docker compose stop 来停止容器,因为这么做需要额外的时间等待容器停止;docker compose up -d 直接升级容器时会自动停止并立刻重建新的容器,完全没有必要浪费那些时间。  docker image prune  # prune 命令用来删除不再使用的 docker 对象。删除所有未被 tag 标记和未被容器使用的镜像 

提示:

WARNING! This will remove all dangling images. Are you sure you want to continue? [y/N] 

输入 y

利用 Docker 搭建的应用,更新非常容易~

8.3 卸载 SyncClipboard

同样进入安装页面,先停止所有容器。

cd /root/data/docker_data/syncclipboard  docker compose down  cd ..  rm -rf /root/data/docker_data/syncclipboard  # 完全删除 

可以卸载得很干净。

9. 常见问题及注意点

目前暂时没啥问题,大家有问题欢迎评论区交流。

10. 结尾

祝大家用得开心,有问题可以去 GitHub 提 Issues,也可以在评论区互相交流探讨。

同时,有能力给项目做贡献的同学,也欢迎积极加入到 项目 中来,贡献自己的一份力量!

最后,感谢开发人员们的辛苦付出,让我们能用到这么优秀的项目!

参考资料

官方GitHub:https://github.com/Jeric-X/SyncClipboard