Skip to content

Instantly share code, notes, and snippets.

@ZiuChen
Created February 12, 2026 07:41
Show Gist options
  • Select an option

  • Save ZiuChen/0eb0fa14e6f6c6414990cfc4b56f3148 to your computer and use it in GitHub Desktop.

Select an option

Save ZiuChen/0eb0fa14e6f6c6414990cfc4b56f3148 to your computer and use it in GitHub Desktop.
AirDrop - uTools: Share specified files, images, or text directly to nearby devices via macOS AirDrop on uTools quickcommand plugin.
{
"program": "quickcommand",
"features": {
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAAAXNSR0IArs4c6QAAA7BJREFUeF7t278vc1EYB/BvdSDEgMGPhgEdJCQmJj82bST+hRoMYkLSTSJhNBCDGAz+BRM2PyYWA0MTLKRFIhKR+DFQeeRt8l6uOu3T45687/eOnOfccz597nnObe8NAciCR9ECIQIWbfcRSECdHwGVfgQkoFZAGc81kIBKAWU4M5CASgFlODOQgEoBZTgzkIBKAWU4M/BfBSwvL8f29vbH9IaGhvDy8qKcqp1wZzPw9PQUbW1tH7M+Pz9HNBq1I6Ds1UnAzc1NxGIxz9S2trYQj8eV0y19uFOActmenJygvb3dd6ZnZ2fo7Ox06nJ2CnBnZwf9/f0IhWRYX49sNou9vT0MDg6WPpWK7NEJwFzBGBgYMJrG7u6uM4XFCcBcwfgu8z6rSia6UlgCB/QrGEZpCMCFwhIYoGTb/v6+b8GorKxEdXW1x/Hh4QGPj49fbKWw9PX1QbIyiCNQwIqKCt+CMTExgYWFBY9HMpnEysqKr5Fssl9fX4Pwc/NHpcnJSSwuLnpApqamsLS0FAhSvpMGloH5BkVAZZ4Q8A+gFIq6ujpIUaivr0dZWZkv7cHBgefvpoC9vb2+/b29veHm5gZPT0+4vb21WmCsXsLr6+sYGRlBTU1N3pz8vP8zBfyp8t7f32NjYwOJREJ5TXwfbg1wfn4eMzMzRgO3BZg7+ezsLObm5ozGUmgja4By+cg2xeSwDSj7x6qqKpOhFNzGCqDc2z4/PxsPxjagDEQ+TBtfyloBbG5uxsXFhQcwEokgk8kYoZqugd911tTUhHQ67fl3S0sLLi8vjc5fSCMCFqLl05aABPwqwEtYeS9MQAKyCquWVm5jVHwAAQloLMB9oDGVf0MnAbu6utDT0+MZ8eHhIY6Pj42m+99vY4yU8jQioFKQgATUbaSVfmAGKgUJSEBewqoc0N7KqU4OcA0koPJHJQISUJcDXAN1furvA5WnZxEhINdAXQ40NDTg6urK08no6Cju7u50HRtG19bWQh6t+/tobGzE9fW1YQ/mzax8oSoPC8lDji4d8nDnT88TFjNeK4AykKOjI3R3dxczppLHpFIpdHR0lLxf6dAa4NjYGFZXVxEOh60M3LRTef1hfHwca2trpiEFtbMGKKMYHh7G8vIyWltbCxpUqRpL5k1PT0PehrJ1WAXMDVqyUBZ203fhtJOVtU4K1m+8fPMrgFoQl+MJqPx0CEhApYAynBlIQKWAMpwZSEClgDKcGUhApYAynBlIQKWAMpwZSEClgDL8HZ4Zzx+VzykmAAAAAElFTkSuQmCC",
"explain": "Airdrop",
"platform": [
"darwin"
],
"mainPush": false,
"cmds": [
{
"type": "over",
"label": "Airdrop"
},
{
"type": "img",
"label": "Airdrop"
},
{
"type": "files",
"label": "Airdrop"
}
],
"mainHide": true,
"code": "professional_350a013f"
},
"output": "ignore",
"tags": [
"实用工具"
],
"cmd": "const { spawn } = require('child_process')\nconst { writeFile } = require('fs/promises')\nconst { join } = require('path')\nconst { tmpdir } = require('os')\n\n ; (async () => {\n try {\n const args = await toAriDropArgs(quickcommand.enterData)\n\n if (!args || args.length === 0) {\n throw new Error('参数无效')\n }\n\n // 执行 Swift 桥接逻辑\n await callSwiftAirDrop(args)\n } catch (error) {\n console.error('AirDrop 出错:', error)\n utools.showNotification(`AirDrop 出错: ${error.message}`)\n }\n })()\n\n/**\n * 将不同类型的数据转换为可供 Swift 消费的参数\n */\nasync function toAriDropArgs({ type, payload }) {\n try {\n switch (type) {\n case 'files': {\n // payload 为文件对象数组\n return payload.map((f) => f.path)\n }\n\n case 'img': {\n // payload 为 base64,存为临时文件以供 AirDrop 识别为图片\n const tempImgPath = join(tmpdir(), `airdrop_temp_img_${Date.now()}.png`)\n const base64Data = payload.replace(/^data:image\\/\\w+;base64,/, '')\n await writeFile(tempImgPath, base64Data, 'base64')\n return [tempImgPath]\n }\n\n case 'text':\n case 'over':\n case 'regex': {\n // 处理文本或划词\n if (typeof payload === 'string') {\n return [payload]\n }\n }\n\n default: {\n throw new Error('不支持的数据类型')\n }\n }\n } catch (err) {\n console.error('AirDrop 脚本运行报错:', err)\n return []\n }\n}\n\n/**\n * 唤起 Swift 解释器执行 Native 逻辑\n */\nfunction callSwiftAirDrop(args) {\n const swiftCode = `\nimport AppKit\n\n// AirDrop 分享服务的 Delegate\nclass AirDropDelegate: NSObject, NSSharingServiceDelegate {\n var didComplete = false\n \n func sharingService(_ sharingService: NSSharingService, didShareItems items: [Any]) {\n print(\"✅ AirDrop 分享成功\")\n didComplete = true\n NSApp.stop(nil)\n }\n \n func sharingService(_ sharingService: NSSharingService, didFailToShareItems items: [Any], error: Error) {\n print(\"❌ AirDrop 分享失败: \\\\(error.localizedDescription)\")\n didComplete = true\n NSApp.stop(nil)\n }\n \n func sharingService(_ sharingService: NSSharingService, sourceWindowForShareItems items: [Any], \n sharingContentScope: UnsafeMutablePointer<NSSharingService.SharingContentScope>) -> NSWindow? {\n let window = NSWindow(\n contentRect: NSRect(x: 0, y: 0, width: 1, height: 1),\n styleMask: [.closable],\n backing: .buffered,\n defer: false\n )\n window.center()\n window.level = .popUpMenu\n window.makeKeyAndOrderFront(nil)\n return window\n }\n}\n\n// 1. 设置为 accessory 模式以避免在 Dock 显示\nlet app = NSApplication.shared\napp.setActivationPolicy(.accessory)\n\nlet arguments = CommandLine.arguments.dropFirst()\nvar items: [Any] = []\n\n// 2. 解析参数为可分享的项目\nfor arg in arguments {\n if arg.hasPrefix(\"http://\") || arg.hasPrefix(\"https://\") {\n if let url = URL(string: arg) { items.append(url) }\n } else if FileManager.default.fileExists(atPath: (arg as NSString).expandingTildeInPath) {\n items.append(URL(fileURLWithPath: (arg as NSString).expandingTildeInPath))\n } else {\n items.append(arg) // 纯文本\n }\n}\n\nguard !items.isEmpty else {\n print(\"❌ 没有可分享的内容\")\n exit(1)\n}\n\n// 3. 创建 AirDrop 分享服务(关键:直接使用 .sendViaAirDrop 而不是 Picker)\nguard let service = NSSharingService(named: .sendViaAirDrop) else {\n print(\"❌ 无法创建 AirDrop 服务\")\n exit(2)\n}\n\n// 4. 检查是否可以分享\nguard service.canPerform(withItems: items) else {\n print(\"❌ 无法通过 AirDrop 分享这些内容\")\n exit(3)\n}\n\n// 5. 设置 delegate 并执行分享\nlet delegate = AirDropDelegate()\nservice.delegate = delegate\n\n// 6. 激活应用并执行分享\nNSApp.activate(ignoringOtherApps: true)\nservice.perform(withItems: items)\n\n// 7. 运行主循环直到分享完成\napp.run()\n`\n\n return new Promise((resolve, reject) => {\n const child = spawn('swift', ['-', ...args], {\n stdio: ['pipe', 'inherit', 'inherit']\n })\n\n child.stdin.write(swiftCode)\n child.stdin.end()\n\n child.on('exit', (code) => {\n code === 0 ? resolve() : reject(new Error(`Exit code ${code}`))\n })\n })\n}\n",
"scptarg": "",
"charset": {
"scriptCode": "",
"outputCode": ""
},
"customOptions": {
"bin": "",
"argv": "",
"ext": ""
},
"cursorPosition": {
"lineNumber": 158,
"column": 1
},
"order": 7
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment