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(例如 bashzsh)。这种环境差异导致了以下问题:


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

这将使 pythonpython3 都指向同一个解释器。

方法 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 解释器路径、创建符号链接或加载用户环境,可以解决此问题 .