mirror of
https://github.com/jiayouzl/Bitcoin-Monitoring.git
synced 2025-11-25 11:29:33 +08:00
Add boot self-start function
This commit is contained in:
@@ -76,7 +76,7 @@
|
||||
4E9410682EB09F90003658CB /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = 1;
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastSwiftUpdateCheck = 1620;
|
||||
LastUpgradeCheck = 2600;
|
||||
TargetAttributes = {
|
||||
@@ -86,11 +86,12 @@
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 4E94106B2EB09F90003658CB /* Build configuration list for PBXProject "Bitcoin Monitoring" */;
|
||||
developmentRegion = en;
|
||||
developmentRegion = "zh-Hans";
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
"zh-Hans",
|
||||
);
|
||||
mainGroup = 4E9410672EB09F90003658CB;
|
||||
minimizedProjectReferenceProxies = 1;
|
||||
@@ -271,8 +272,8 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||
MARKETING_VERSION = 1.0.3;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MARKETING_VERSION = 1.0.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.mark.test1;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
@@ -304,8 +305,8 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||
MARKETING_VERSION = 1.0.3;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MARKETING_VERSION = 1.0.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.mark.test1;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
|
||||
20
README.md
20
README.md
@@ -7,7 +7,7 @@
|
||||

|
||||

|
||||
|
||||
一款 macOS 原生菜单栏应用,用于实时监控主流虚拟货币价格,支持 BTC/ETH/BNB/SOL/DOGE 多种币种,之前使用Python写过虽然也蛮好用但最终还是决定用macOS原生语言开发,已经编译了`Intel`与`Apple Silicon`的通用应用,请至[releases](https://github.com/jiayouzl/Bitcoin-Monitoring/releases/latest)下载。
|
||||
一款 macOS 原生菜单栏应用,用于实时监控主流虚拟货币价格,支持 BTC/ETH/BNB/SOL/DOGE 多种币种。之前使用Python写过虽然也蛮好用但最终还是决定用macOS原生语言重写,已经编译了`Intel`与`Apple Silicon`的通用应用,请至[releases](https://github.com/jiayouzl/Bitcoin-Monitoring/releases/latest)下载。
|
||||
|
||||
</div>
|
||||
|
||||
@@ -29,13 +29,14 @@
|
||||
- **状态指示**: 直观显示加载、更新、错误状态
|
||||
- **价格复制功能**: 支持一键复制当前价格到剪贴板
|
||||
- **配置持久化**: 用户设置自动保存,重启后保持配置
|
||||
- **开机自启动**: 可选是否开机自动启动APP
|
||||
|
||||
### 🎨 用户体验
|
||||
- **SF Symbols 图标**: 使用原生 macOS 图标系统
|
||||
- **中文界面**: 完整的中文用户界面
|
||||
- **优雅动画**: 流畅的状态切换动画
|
||||
- **轻量级设计**: 最小化系统资源占用
|
||||
- **后台运行**: 不占用 Dock 空间,专注菜单栏
|
||||
- **SF Symbols 图标**: 使用原生 macOS 图标系统
|
||||
|
||||
### 🛡️ 可靠性
|
||||
- **网络容错**: 完善的网络异常处理机制
|
||||
@@ -46,13 +47,13 @@
|
||||
## 📋 安装要求
|
||||
|
||||
### 系统要求
|
||||
- **操作系统**: macOS 12.4 或更高版本
|
||||
- **操作系统**: macOS 13.1 或更高版本
|
||||
- **架构支持**: Intel 和 Apple Silicon (M1/M2/M3/M4/M5)
|
||||
|
||||
### 开发环境
|
||||
- **开发工具**: Xcode 16.2 或更高版本
|
||||
- **Swift 版本**: Swift 5.0
|
||||
- **部署目标**: macOS 12.4
|
||||
- **部署目标**: macOS 13.1
|
||||
|
||||
### 网络要求
|
||||
- 需要稳定的互联网连接
|
||||
@@ -107,7 +108,7 @@ xcodebuild -project "Bitcoin Monitoring.xcodeproj" -scheme "Bitcoin Monitoring"
|
||||
- 支持 BTC/ETH/BNB/SOL/DOGE 五种主流币种
|
||||
|
||||
4. **复制价格**
|
||||
- **Option + 点击** 币种名称可快速复制当前价格到剪贴板
|
||||
- **Option + 左键点击** 币种名称可快速复制当前价格到剪贴板
|
||||
- 价格格式为 `$XXX.XX`,可直接粘贴使用
|
||||
|
||||
5. **交互菜单**
|
||||
@@ -126,6 +127,7 @@ xcodebuild -project "Bitcoin Monitoring.xcodeproj" -scheme "Bitcoin Monitoring"
|
||||
| 更新时间 | 显示上次成功更新时间 | - |
|
||||
| 刷新价格 | 手动获取最新价格 | `Cmd+R` |
|
||||
| 刷新设置 | 设置刷新的间隔 | - |
|
||||
| 开机启动 | 设置开机自动启动APP | - |
|
||||
| GitHub | 打开仓库查询更新 | - |
|
||||
| 关于 | 查看应用信息和版本 | - |
|
||||
| 退出 | 完全退出应用 | `Cmd+Q` |
|
||||
@@ -310,14 +312,6 @@ curl "https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT"
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
|
||||
**⭐ 如果这个项目对你有帮助,请给它一个 Star!**
|
||||
|
||||
Made with ❤️ for the Bitcoin community
|
||||
|
||||
</div>
|
||||
|
||||
## ⭐ Star History
|
||||
|
||||
[](https://www.star-history.com/#jiayouzl/Bitcoin-Monitoring&Date)
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import ServiceManagement
|
||||
|
||||
/// 应用配置管理类
|
||||
/// 负责管理用户的刷新间隔设置和其他应用配置
|
||||
@@ -19,12 +20,15 @@ class AppSettings: ObservableObject {
|
||||
@Published var refreshInterval: RefreshInterval = .thirtySeconds
|
||||
/// 当前选中的币种
|
||||
@Published var selectedSymbol: CryptoSymbol = .btc
|
||||
/// 是否开机自启动
|
||||
@Published var launchAtLogin: Bool = false
|
||||
|
||||
// MARK: - Private Properties
|
||||
|
||||
private let defaults = UserDefaults.standard
|
||||
private let refreshIntervalKey = "BTCRefreshInterval"
|
||||
private let selectedSymbolKey = "SelectedCryptoSymbol"
|
||||
private let launchAtLoginKey = "LaunchAtLogin"
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
@@ -101,8 +105,14 @@ class AppSettings: ObservableObject {
|
||||
saveSelectedSymbol(.btc)
|
||||
}
|
||||
|
||||
// 加载开机自启动设置
|
||||
launchAtLogin = defaults.bool(forKey: launchAtLoginKey)
|
||||
|
||||
// 检查实际的自启动状态并同步
|
||||
checkAndSyncLaunchAtLoginStatus()
|
||||
|
||||
#if DEBUG
|
||||
print("🔧 [AppSettings] 配置加载完成 - 刷新间隔: \(refreshInterval.displayText), 币种: \(selectedSymbol.displayName)")
|
||||
print("🔧 [AppSettings] 配置加载完成 - 刷新间隔: \(refreshInterval.displayText), 币种: \(selectedSymbol.displayName), 开机自启动: \(launchAtLogin)")
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -123,6 +133,13 @@ class AppSettings: ObservableObject {
|
||||
#if DEBUG
|
||||
print("🔧 [AppSettings] 重置完成 - 刷新间隔: \(refreshInterval.displayText), 币种: \(selectedSymbol.displayName)")
|
||||
#endif
|
||||
|
||||
// 重置开机自启动设置
|
||||
launchAtLogin = false
|
||||
defaults.set(false, forKey: launchAtLoginKey)
|
||||
|
||||
// 禁用开机自启动
|
||||
toggleLoginItem(enabled: false)
|
||||
}
|
||||
|
||||
/// 保存用户选择的刷新间隔
|
||||
@@ -141,4 +158,81 @@ class AppSettings: ObservableObject {
|
||||
#endif
|
||||
defaults.set(symbol.rawValue, forKey: selectedSymbolKey)
|
||||
}
|
||||
|
||||
// MARK: - 开机自启动相关方法
|
||||
|
||||
/// 切换开机自启动状态
|
||||
/// - Parameter enabled: 是否启用开机自启动
|
||||
func toggleLoginItem(enabled: Bool) {
|
||||
// 检查 macOS 版本是否支持 SMAppService (macOS 13+)
|
||||
if #available(macOS 13.0, *) {
|
||||
do {
|
||||
if enabled {
|
||||
try SMAppService.mainApp.register()
|
||||
#if DEBUG
|
||||
print("🔧 [AppSettings] ✅ 开机自启动已启用")
|
||||
#endif
|
||||
} else {
|
||||
try SMAppService.mainApp.unregister()
|
||||
#if DEBUG
|
||||
print("🔧 [AppSettings] ❌ 开机自启动已禁用")
|
||||
#endif
|
||||
}
|
||||
|
||||
// 保存到 UserDefaults
|
||||
launchAtLogin = enabled
|
||||
defaults.set(enabled, forKey: launchAtLoginKey)
|
||||
|
||||
} catch {
|
||||
#if DEBUG
|
||||
print("🔧 [AppSettings] ⚠️ 设置开机自启动失败: \(error.localizedDescription)")
|
||||
#endif
|
||||
|
||||
// 如果操作失败,恢复到之前的状态
|
||||
let actualStatus = SMAppService.mainApp.status
|
||||
launchAtLogin = (actualStatus == .enabled)
|
||||
defaults.set(launchAtLogin, forKey: launchAtLoginKey)
|
||||
}
|
||||
} else {
|
||||
// 对于低于 macOS 13 的版本,显示警告信息
|
||||
#if DEBUG
|
||||
print("🔧 [AppSettings] ⚠️ 当前 macOS 版本不支持 SMAppService,无法设置开机自启动")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// 检查并同步开机自启动状态
|
||||
/// 确保应用内部状态与系统实际状态保持一致
|
||||
private func checkAndSyncLaunchAtLoginStatus() {
|
||||
guard #available(macOS 13.0, *) else {
|
||||
#if DEBUG
|
||||
print("🔧 [AppSettings] ⚠️ 当前 macOS 版本不支持 SMAppService")
|
||||
#endif
|
||||
return
|
||||
}
|
||||
|
||||
let actualStatus = SMAppService.mainApp.status
|
||||
let isEnabled = (actualStatus == .enabled)
|
||||
|
||||
// 如果系统状态与应用内部状态不一致,则同步
|
||||
if isEnabled != launchAtLogin {
|
||||
launchAtLogin = isEnabled
|
||||
defaults.set(isEnabled, forKey: launchAtLoginKey)
|
||||
|
||||
#if DEBUG
|
||||
print("🔧 [AppSettings] 🔄 已同步开机自启动状态: \(isEnabled)")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取当前开机自启动状态
|
||||
/// - Returns: 是否已启用开机自启动
|
||||
func isLaunchAtLoginEnabled() -> Bool {
|
||||
guard #available(macOS 13.0, *) else {
|
||||
return false
|
||||
}
|
||||
|
||||
let actualStatus = SMAppService.mainApp.status
|
||||
return actualStatus == .enabled
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,6 +264,18 @@ class BTCMenuBarApp: NSObject, ObservableObject {
|
||||
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
|
||||
// 添加开机启动开关
|
||||
let launchAtLoginTitle = appSettings.launchAtLogin ? "✓ 开机启动" : "开机启动"
|
||||
let launchAtLoginItem = NSMenuItem(title: launchAtLoginTitle, action: #selector(toggleLaunchAtLogin), keyEquivalent: "")
|
||||
if let powerImage = NSImage(systemSymbolName: "tv", accessibilityDescription: "开机启动") {
|
||||
powerImage.size = NSSize(width: 16, height: 16)
|
||||
launchAtLoginItem.image = powerImage
|
||||
}
|
||||
launchAtLoginItem.target = self
|
||||
menu.addItem(launchAtLoginItem)
|
||||
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
|
||||
#if DEBUG
|
||||
// 添加重置设置按钮(仅在 Debug 模式下显示)
|
||||
let resetItem = NSMenuItem(title: "重置设置", action: #selector(resetSettings), keyEquivalent: "")
|
||||
@@ -474,6 +486,48 @@ class BTCMenuBarApp: NSObject, ObservableObject {
|
||||
}
|
||||
|
||||
|
||||
// 切换开机自启动状态
|
||||
@objc private func toggleLaunchAtLogin() {
|
||||
let newState = !appSettings.launchAtLogin
|
||||
|
||||
// 检查 macOS 版本兼容性
|
||||
if #available(macOS 13.0, *) {
|
||||
// 显示确认对话框
|
||||
let alert = NSAlert()
|
||||
alert.messageText = newState ? "启用开机自启动" : "禁用开机自启动"
|
||||
alert.informativeText = newState ?
|
||||
"应用将在系统启动时自动运行,您也可以随时在系统偏好设置中更改此选项。" :
|
||||
"应用将不再在系统启动时自动运行。"
|
||||
alert.alertStyle = .informational
|
||||
alert.addButton(withTitle: "确定")
|
||||
alert.addButton(withTitle: "取消")
|
||||
|
||||
let response = alert.runModal()
|
||||
if response == .alertFirstButtonReturn {
|
||||
// 用户确认,执行切换
|
||||
appSettings.toggleLoginItem(enabled: newState)
|
||||
|
||||
// 显示结果反馈
|
||||
let resultAlert = NSAlert()
|
||||
resultAlert.messageText = newState ? "开机自启动已启用" : "开机自启动已禁用"
|
||||
resultAlert.informativeText = newState ?
|
||||
"Bitcoin Monitoring 将在下次系统启动时自动运行。" :
|
||||
"Bitcoin Monitoring 不会在系统启动时自动运行。"
|
||||
resultAlert.alertStyle = .informational
|
||||
resultAlert.addButton(withTitle: "确定")
|
||||
resultAlert.runModal()
|
||||
}
|
||||
} else {
|
||||
// 不支持的系统版本
|
||||
let alert = NSAlert()
|
||||
alert.messageText = "系统版本不支持"
|
||||
alert.informativeText = "开机自启动功能需要 macOS 13.0 (Ventura) 或更高版本。"
|
||||
alert.alertStyle = .warning
|
||||
alert.addButton(withTitle: "确定")
|
||||
alert.runModal()
|
||||
}
|
||||
}
|
||||
|
||||
// 退出应用
|
||||
@objc private func quitApp() {
|
||||
NSApplication.shared.terminate(nil)
|
||||
|
||||
Reference in New Issue
Block a user