靠近自动解锁,远离即刻锁定:BLEUnlock让你的Mac更智能

BLEUnlock

BLEUnlock 是一款轻量级的 macOS 菜单栏实用工具。它通过检测您 iPhone、Apple Watch 或其他蓝牙低功耗(BLE)设备的接近状态,来自动锁定或解锁您的 Mac 屏幕。无需 iPhone 配套应用,利用您已有的设备即可实现智能化的安全防护。

功能特性

  • 自动解锁:当配对的 BLE 设备靠近 Mac 时,自动为您解除登录屏幕锁定。
  • 自动锁定:当配对的 BLE 设备离开 Mac 一定距离后,自动锁定屏幕。
  • 广泛兼容:支持任何定期发送信号且具有静态 MAC 地址的 BLE 设备,无需专用 App。
  • 脚本扩展:支持在锁定/解锁事件发生时运行自定义脚本。
  • 媒体控制:可选在您离开或返回时,自动暂停或恢复音乐/视频播放。
  • 唤醒屏幕:可选在设备靠近时唤醒处于睡眠状态的显示器。
  • 安全存储:您的登录密码被安全地存储在系统钥匙串中。
  • 手动控制:提供“立即锁定”功能,无视设备距离强制锁定。

安装指南

使用 Homebrew Cask 安装(推荐)

打开终端,执行以下命令:

brew install bleunlock

手动安装

  1. 从项目的 Releases 页面 下载最新的 .zip 文件。
  2. 解压下载的文件。
  3. 将解压出的 BLEUnlock.app 拖拽到“应用程序”文件夹中。

系统要求

  • 支持蓝牙低功耗(Bluetooth Low Energy)的 Mac。
  • macOS 10.13 (High Sierra) 或更高版本。
  • iPhone 5s 或更新机型、Apple Watch(所有型号),或其他符合要求的 BLE 设备。

使用说明

首次运行 BLEUnlock 需要进行以下设置:

  1. 授予权限:应用会依次请求必要的系统权限,请务必全部允许:

    • 蓝牙:用于扫描和连接设备。
    • 辅助功能:用于模拟按键以解锁屏幕。需要在“系统偏好设置 > 安全性与隐私 > 隐私 > 辅助功能”中启用 BLEUnlock。
    • 钥匙串:(如果弹出)请选择“始终允许”,以便在锁定状态下也能访问密码。
    • 通知:(可选)用于显示操作状态提示。
  2. 输入密码:应用会提示您输入当前 Mac 的用户登录密码。此密码将被加密存储于钥匙串中,仅用于自动解锁。

  3. 选择设备

    • 点击菜单栏中的 BLEUnlock 图标。
    • 从“设备”子菜单中,选择“扫描设备...”。
    • 从扫描到的列表中选择您要用于触发解锁/锁定的 BLE 设备(如您的 iPhone)。
    • 配对成功后,图标将变为实心,功能即刻生效。
  4. 配置选项(通过菜单栏图标):

    • 解锁信号强度:设置触发解锁所需的蓝牙信号强度阈值。值越大,设备需要离 Mac 越近才能解锁。
    • 锁定信号强度:设置触发锁定的蓝牙信号强度阈值。值越小,设备稍一远离 Mac 就会锁定。
    • 锁定延迟:设备远离后,等待多久才执行锁定操作。
    • 触发脚本:设置锁定或解锁事件发生时运行的脚本路径。
    • 唤醒显示器:启用后,设备靠近时可唤醒睡眠的屏幕。
    • 暂停媒体:启用后,离开时自动暂停播放,返回时自动恢复。

核心代码

以下是项目中的部分核心代码,展示了其基础工作原理。

1. 低层级屏幕与系统控制 (lowlevel.c)
此文件包含了控制显示器睡眠/唤醒以及立即锁定屏幕的底层 C 函数。

#include "lowlevel.h"
#include <IOKit/pwr_mgt/IOPMLib.h>
#include <IOKit/IOKitLib.h>

// 唤醒显示器
void wakeDisplay(void)
{
    static IOPMAssertionID assertionID;
    // 声明一个用户活动,防止系统进入睡眠,并唤醒显示器
    IOPMAssertionDeclareUserActivity(CFSTR("BLEUnlock"), kIOPMUserActiveLocal, &assertionID);
}

// 使显示器进入睡眠
void sleepDisplay(void)
{
    // 通过 IORegistry 访问显示器管理服务
    io_registry_entry_t reg = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/IOResources/IODisplayWrangler");
    if (reg) {
        // 设置属性请求显示器空闲(睡眠)
        IORegistryEntrySetCFProperty(reg, CFSTR("IORequestIdle"), kCFBooleanTrue);
        IOObjectRelease(reg); // 释放资源
    }
}

2. 低层级函数头文件 (lowlevel.h)
定义了可供 Swift 代码调用的 C 函数接口。

#ifndef lowlevel_h
#define lowlevel_h
#include <stdbool.h>

void sleepDisplay(void); // 睡眠显示器
void wakeDisplay(void);  // 唤醒显示器
int SACLockScreenImmediate(void); // 立即锁定屏幕(函数实现在其他文件)

#endif /* lowlevel_h */

3. 媒体远程控制接口 (MediaRemote.h)
定义了用于控制 macOS 全局媒体播放(如音乐、视频)的私有框架函数。

#include <CoreFoundation/CoreFoundation.h>

// 媒体命令枚举
typedef enum {
    MRCommandPlay, // 播放命令
    MRCommandPause, // 暂停命令
} MRCommand;

// 获取当前播放状态的回调块类型
typedef void (^MRMediaRemoteGetNowPlayingApplicationIsPlayingCompletion)(Boolean isPlaying);

// 函数声明:获取是否正在播放
void MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_queue_t queue, MRMediaRemoteGetNowPlayingApplicationIsPlayingCompletion completion);
// 函数声明:发送播放/暂停命令
Boolean MRMediaRemoteSendCommand(MRCommand command, id userInfo);

4. 启动器代理 (AppDelegate.m)
此代码属于应用的“启动器”组件,用于确保主应用只有一个实例运行。

#import "AppDelegate.h"

@interface AppDelegate ()
@end

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // 获取当前 bundle identifier (例如 com.example.BLEUnlock.Launcher)
    NSString *id = [[NSBundle mainBundle] bundleIdentifier];
    // 推导出主应用的 bundle identifier (去掉 .Launcher)
    NSString *mainId = [id stringByReplacingOccurrencesOfString:@".Launcher" withString:@""];
    
    // 检查主应用是否已经在运行
    if ([NSRunningApplication runningApplicationsWithBundleIdentifier:mainId].count > 0) {
        [NSApp terminate:self]; // 如果已运行,则终止启动器
    }

    // 构建主应用的路径 (向上回退四级目录)
    NSString *path = [[NSBundle mainBundle] bundlePath];
    NSMutableArray *components = [NSMutableArray arrayWithArray:[path pathComponents]];
    [components removeLastObject]; // 移除 macOS/
    [components removeLastObject]; // 移除 Contents/
    [components removeLastObject]; // 移除 _CodeSignature 或类似目录
    [components removeLastObject]; // 移除 BLEUnlock Launcher.app
    NSString *mainPath = [NSString pathWithComponents:components]; // 得到 BLEUnlock.app 的路径
    
    // 启动主应用程序
    [[NSWorkspace sharedWorkspace] launchApplication:mainPath];
    // 终止启动器自身
    [NSApp terminate:self];
}

- (void)applicationWillTerminate:(NSNotification *)aNotification {
    // 终止前的清理工作(如有)
}

@end

kC6Ey/YuBG2vd8EVZfHu7L/x107n3ZMNPCO+hvaEEDo=

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容