mac自定义链接协议

在 macOS 上自定义一个链接协议(URL Scheme),并使其在访问时自动执行对应的脚本,可以通过以下步骤实现:


1. 创建 AppleScript 脚本

首先,使用 macOS 自带的 Script Editor 编写一个 AppleScript 脚本。这个脚本将作为处理自定义协议的核心逻辑。

例如,创建一个简单的脚本,当触发时会弹出一个对话框:

on open location this_URL
    display dialog "你访问了自定义协议:" & this_URL
end open location

保存脚本为应用程序格式:

  • 在 Script Editor 中,选择 文件 > 导出。
  • 将文件类型设置为 应用程序,并保存到合适的位置,比如 /Applications/MyCustomProtocol.app 。

2. 修改应用程序的 Info.plist 文件

为了让 macOS 识别你的自定义协议,需要修改刚刚生成的应用程序的 Info.plist 文件。

  1. 右键点击生成的 .app 文件,选择 显示包内容。

  2. 进入 Contents 文件夹,找到并编辑 Info.plist 文件(可以使用 Xcode 或文本编辑器)。

  3. 添加以下内容以声明支持的 URL Scheme:

    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleURLName</key>
            <string>com.example.myprotocol</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>myprotocol</string>
            </array>
        </dict>
    </array>
    • CFBundleURLName 是协议的唯一标识符。
    • CFBundleURLSchemes 定义了协议名称,例如 myprotocol://。
  4. 保存并关闭 Info.plist 文件。


3. 注册协议

macOS 会自动识别已安装应用程序中声明的 URL Scheme。如果需要手动刷新 Launch Services 数据库,可以在终端运行以下命令:

/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -f /Applications/MyCustomProtocol.app

这将确保系统能够识别你的自定义协议 。


4. 测试自定义协议

打开 Safari 或其他浏览器,在地址栏输入:

myprotocol://test

如果一切配置正确,系统会启动 MyCustomProtocol.app,并触发 AppleScript 脚本中的 open location 方法,显示对话框 。


5. 扩展:结合 Shell 脚本

如果你希望在触发协议时执行更复杂的任务(如运行 Shell 脚本),可以修改 AppleScript 脚本以调用外部脚本。例如:

on open location this_URL
    do shell script "/path/to/your/script.sh " & quoted form of this_URL
end open location

这样,当访问 myprotocol://example 时,script.sh 会被调用,并接收到 URL 参数 。

AppleScript执行python脚本

在 AppleScript 中执行 Python 脚本,可以通过调用系统命令(如 do shell script)来实现。以下是具体的实现步骤和示例代码:


1. 使用 do shell script 执行 Python 脚本

AppleScript 提供了 do shell script 命令,可以直接运行终端命令。通过该命令,可以调用 Python 解释器并执行指定的 Python 脚本文件。

示例代码

set pythonScriptPath to "/path/to/your_script.py"
do shell script "python3 " & quoted form of pythonScriptPath
  • pythonScriptPath 是 Python 脚本的绝对路径。
  • quoted form of 用于确保路径中的空格或特殊字符不会导致命令解析错误 。

2. 将 Python 脚本内容直接嵌入 AppleScript

如果 Python 脚本较短,可以直接将脚本内容嵌入 AppleScript 中,而无需单独保存为 .py 文件。

示例代码

set pythonCode to "
import sys
print('Hello from Python!')
"
do shell script "echo " & quoted form of pythonCode & " | python3"
  • 这里使用 echo 将 Python 代码传递给 python3 解释器。
  • 适合简单的脚本逻辑,但如果脚本较长,建议使用外部文件 。

3. 处理 Python 脚本的输出

AppleScript 可以捕获 Python 脚本的输出,并将其存储到变量中进行后续处理。

示例代码

set pythonScriptPath to "/path/to/your_script.py"
set scriptOutput to do shell script "python3 " & quoted form of pythonScriptPath
display dialog "Python 脚本输出:" & scriptOutput
  • scriptOutput 存储了 Python 脚本的标准输出。
  • display dialog 用于显示输出内容 。

4. 示例:结合 AppleScript 和 Python 实现功能

假设有一个 Python 脚本 example.py,其内容如下:

# example.py
import sys
 
def main():
    print("Hello from Python!")
    return 0
 
if __name__ == "__main__":
    sys.exit(main())

在 AppleScript 中调用该脚本并捕获输出:

set pythonScriptPath to "/path/to/example.py"
try
    set scriptOutput to do shell script "python3 " & quoted form of pythonScriptPath
    display dialog "Python 脚本输出:" & scriptOutput
on error errMsg
    display dialog "执行 Python 脚本时出错:" & errMsg
end try

以下是修改后的 AppleScript 脚本,将通过自定义协议获取到的参数 this_URL 传递给 Python 脚本,并执行该脚本:

修改后的 AppleScript 脚本

on open location this_URL
    -- 定义 Python 脚本的路径
    set pythonScriptPath to "/path/to/your_script.py"
    
    -- 将 URL 参数传递给 Python 脚本
    do shell script "python3 " & quoted form of pythonScriptPath & " " & quoted form of this_URL
    
    -- 显示对话框以确认操作
    display dialog "你访问了自定义协议:" & this_URL
end open location

关键点解析

  1. do shell script 的使用

    • 使用 do shell script 调用系统命令。
    • quoted form of 确保路径和参数中的空格或特殊字符不会导致命令解析错误 。
  2. 传递参数

    • this_URL 是通过自定义协议传递的参数(例如 myprotocol://example)。
    • 将 this_URL 作为命令行参数传递给 Python 脚本。
  3. Python 脚本路径

    • 替换 /path/to/your_script.py 为实际的 Python 脚本路径。
  4. 对话框提示

    • 使用 display dialog 显示用户友好的提示信息 。

修改后的脚本

#!/usr/bin/env python3
 
import sys
import os
import subprocess
from urllib.parse import unquote
 
def open_file(file_path):
    # 检查文件是否存在
    if not os.path.exists(file_path):
        print(f"错误:文件 '{file_path}' 不存在。")
        sys.exit(1)
 
    # 使用 macOS 的 `open` 命令调用默认应用程序打开文件
    try:
        subprocess.run(["open", file_path], check=True)
        print(f"文件 '{file_path}' 已使用默认应用程序打开。")
    except subprocess.CalledProcessError as e:
        print(f"错误:无法打开文件 '{file_path}'。详细信息:{e}")
        sys.exit(1)
 
def extract_file_path(url):
    # 提取 `anylink://` 后的文件路径
    if not url.startswith("anylink://"):
        print(f"错误:无效的协议格式。必须以 'anylink://' 开头。")
        sys.exit(1)
 
    # 去掉协议前缀
    file_path = url[len("anylink://"):]
 
    # 对 URL 编码的路径进行解码
    file_path = unquote(file_path)
 
    return file_path
 
if __name__ == "__main__":
    # 检查是否提供了 URL 参数
    if len(sys.argv) < 2:
        print("错误:未提供参数。用法: python3 anylink.py <anylink://文件路径>")
        sys.exit(1)
 
    # 获取 URL 参数
    url = sys.argv[1]
 
    # 提取文件路径
    file_path = extract_file_path(url)
 
    # 调用函数打开文件
    open_file(file_path)

关键点解析

  1. 提取文件路径

    • 使用字符串操作去掉 anylink:// 前缀。
    • 使用 urllib.parse.unquote 解码 URL 编码的路径(例如,将 %20 转换为空格)。
  2. 检查协议格式

    • 确保输入的 URL 以 anylink:// 开头。如果格式不正确,脚本会报错并退出。
  3. 文件路径处理

    • 提取的文件路径会被传递给 open_file 函数,由其检查文件是否存在并调用 open 命令打开文件 。
  4. 错误处理

    • 如果文件不存在或 open 命令执行失败,脚本会输出详细的错误信息并退出。

运行流程

  1. 触发自定义协议
    假设自定义协议为 anylink:///Users/username/Documents/example.txt,当用户点击该链接时,AppleScript 将 URL 作为参数传递给 Python 脚本。

  2. Python 脚本处理参数

    • 脚本提取 anylink:// 后的文件路径。
    • 解码 URL 编码的路径。
    • 检查文件是否存在,并调用 macOS 的默认应用程序打开文件。

测试步骤

  1. 保存脚本
    将上述代码保存为 anylink.py,并确保其具有可执行权限:

    chmod +x anylink.py
  2. 触发自定义协议
    在浏览器中访问以下链接:

    anylink:///Users/username/Documents/example.txt
    

    或者通过 AppleScript 调用 Python 脚本:

    do shell script "python3 /path/to/anylink.py 'anylink:///Users/username/Documents/example.txt'"
  3. 验证结果

    • 确保文件被成功打开。
    • 检查终端输出,确认脚本的执行过程。

注意事项

  1. URL 编码
    如果文件路径中包含特殊字符(如空格、中文等),需要确保它们在 URL 中正确编码。例如,空格应编码为 %20。

  2. 绝对路径
    文件路径必须是绝对路径,否则可能导致文件找不到的错误 。

  3. 安全性

    • 验证输入的 URL 格式,防止恶意输入。
    • 确保脚本仅处理可信来源的参数。

通过以上修改,anylink.py 脚本可以成功提取 anylink:// 协议中的文件路径,并使用 macOS 的默认应用程序打开该文件 .

相关问题

我在命令行执行python是正常的,但是在脚本编辑器中执行do shell script "python /Users/xiangyu/anylink/anylink.py 'anylink:///Users/xiangyu/Documents/pdftest/test.pdf'"会提示error "sh: python: command not found" number 127,若修改为python3就正常,这是为什么

这个问题的根本原因是 macOS 的 do shell script 命令在执行时,默认使用的是系统的 /bin/sh Shell 环境,而不是你通常在终端中使用的 Shell(例如 bash 或 zsh)。这种环境差异导致了以下问题:


1. Python 的路径问题

在 macOS 上,默认的 python 命令可能并未正确配置到系统路径中。具体原因如下:

  • 在较新的 macOS 版本中,Apple 已经移除了系统自带的 Python 2,并且默认不再提供 python 命令。
  • 如果你安装了 Python 3(例如通过 Homebrew 或官方安装包),它通常会提供一个 python3 命令,但不会自动创建 python 的符号链接。

因此,在终端中运行 python 可能正常,因为你的用户环境(如 .bashrc 或 .zshrc)中已经配置了别名或 PATH 环境变量,指向了正确的 Python 解释器。但在 do shell script 中,用户的 Shell 配置文件(如 .bashrc 或 .zshrc)不会被加载,导致系统找不到 python 命令。


2. 使用 python3 的原因

当你将命令改为 python3 时,系统能够找到 python3,因为它通常安装在标准路径(如 /usr/local/bin/python3 或 /opt/homebrew/bin/python3),并且这些路径是全局可用的。因此,do shell script "python3 ..." 能够正常工作。


解决方案

方法 1:明确指定 Python 解释器路径

为了避免依赖系统 PATH,可以直接在脚本中指定 Python 解释器的完整路径。例如:

do shell script "/usr/local/bin/python3 /Users/xiangyu/anylink/anylink.py 'anylink:///Users/xiangyu/Documents/pdftest/test.pdf'"

你可以通过以下命令找到 Python 3 的完整路径:

which python3

方法 2:为 python 创建符号链接

如果你希望继续使用 python 命令,可以手动创建一个符号链接,将 python 指向 python3。例如:

sudo ln -s /usr/local/bin/python3 /usr/local/bin/python

这将使 python 和 python3 都指向同一个解释器。

方法 3:修改 AppleScript 脚本以加载用户环境

如果希望 do shell script 加载用户的 Shell 配置文件(如 .bashrc 或 .zshrc),可以在命令前添加 source 操作。例如:

do shell script "source ~/.zshrc; python /Users/xiangyu/anylink/anylink.py 'anylink:///Users/xiangyu/Documents/pdftest/test.pdf'"

注意:这种方法需要确保你的 Shell 配置文件中正确设置了 python 的别名或 PATH。


总结

error "sh: python: command not found" 的原因是 do shell script 默认使用 /bin/sh 环境,而该环境中没有配置 python 命令。通过明确指定 Python 解释器路径、创建符号链接或加载用户环境,可以解决此问题 .