You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

macOS下打包Java应用的自定义URI处理器适配求助

macOS下Java应用自定义URI处理器配置问题排查与解决

问题背景

我们需要为macOS上的打包Java应用配置自定义URI处理器实现SSO功能:用户浏览器登录后,通过URI携带参数返回Java应用。Windows端已通过注册表实现该逻辑,但macOS端配置后无法触发URI回调。

当前配置

1. Info.plist中的URI Scheme注册

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLName</key>
        <string>com.company.ourscheme</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>ourscheme</string>
        </array>
    </dict>
</array>

2. Info.plist中的CFBundleDocumentTypes配置

<key>CFBundleDocumentTypes</key>
<array>
    <dict>
        <key>CFBundleTypeIconFiles</key>
        <array/>
        <key>CFBundleTypeName</key>
        <string>public.data</string>
        <key>LSHandlerRank</key>
        <string>Alternate</string>
        <key>LSItemContentTypes</key>
        <array>
            <string>public.data</string>
        </array>
    </dict>
</array>

3. Java代码中的URI回调注册

Desktop.getDesktop().setOpenURIHandler((event) -> {
     System.out.println("Open URI: " + event.getURI());
     // 处理URI参数逻辑
});

4. C包装器启动代码

int main(int argc, char *argv[])
{
   // 初始化下方用到的变量...

  char *args[] = {java, concat("-Duser.dir=", userdir), "-Dsun.awt.disablegrab=true", concat("-Xdock:icon=", icon), "-Xdock:name=Our Product", "-Dcom.apple.macos.use-file-dialog-packages=true", "-Dcom.apple.macos.useSmallTabs=true", "-Dapple.laf.useScreenMenuBar=false",     "-Dcom.apple.mrj.application.apple.menu.about.name=Our Product", "-Xms64M", "-Xmx1024M", "-jar", jar, "custom-argument", NULL};
 
  execv(java, args);
  
  return 0;
}

问题现象

  • 应用未运行时,触发ourscheme://testing能启动应用,但回调无响应;
  • 应用已运行时,触发URI会让应用获焦点,但回调仍不触发;
  • 测试ourscheme://file.txt格式URI同样无效。

问题分析与解决方案

1. C包装器的核心影响

macOS的Launch Services会把URI参数传递给应用包的主可执行文件,但当前C包装器用execv启动Java进程时,没有转发Launch Services传入的argv参数。这直接导致:

  • 应用未启动时,Java收不到URI启动参数;
  • 应用已启动时,C包装器没有正确传递Apple Event到Java进程,导致setOpenURIHandler无法接收事件。

2. 修复步骤

步骤1:修改C包装器,转发启动参数

将Launch Services传入的参数合并到Java启动参数中,确保URI能传递到Java进程:

int main(int argc, char *argv[])
{
   // 初始化变量:java, userdir, icon, jar等...

   // 计算新参数数组长度:原Java参数数 + 外部传入参数数 + 1(NULL结尾)
   int baseArgsCount = 14; // 原args数组中除NULL外的元素数量
   int newArgCount = baseArgsCount + (argc - 1) + 1;
   char **newArgs = malloc(newArgCount * sizeof(char*));

   // 复制原Java启动参数
   newArgs[0] = java;
   newArgs[1] = concat("-Duser.dir=", userdir);
   newArgs[2] = "-Dsun.awt.disablegrab=true";
   newArgs[3] = concat("-Xdock:icon=", icon);
   newArgs[4] = "-Xdock:name=Our Product";
   newArgs[5] = "-Dcom.apple.macos.use-file-dialog-packages=true";
   newArgs[6] = "-Dcom.apple.macos.useSmallTabs=true";
   newArgs[7] = "-Dapple.laf.useScreenMenuBar=false";
   newArgs[8] = "-Dcom.apple.mrj.application.apple.menu.about.name=Our Product";
   newArgs[9] = "-Xms64M";
   newArgs[10] = "-Xmx1024M";
   newArgs[11] = "-jar";
   newArgs[12] = jar;
   newArgs[13] = "custom-argument";

   // 转发外部传入的参数(跳过自身程序名argv[0])
   for (int i = 1; i < argc; i++) {
       newArgs[baseArgsCount + i - 1] = argv[i];
   }

   // 添加NULL结尾
   newArgs[newArgCount - 1] = NULL;

   execv(java, newArgs);
   
   // 仅当execv失败时执行内存释放
   free(newArgs);
   return 0;
}

步骤2:调整Java代码,覆盖两种场景

macOS下Java接收URI分两种情况,需同时处理:

  • 应用未启动时:URI作为启动参数传入;
  • 应用已启动时:通过OpenURIHandler回调接收。
public static void main(String[] args) {
    // 处理启动时传入的URI参数
    for (String arg : args) {
        if (arg.startsWith("ourscheme://")) {
            handleURI(URI.create(arg));
        }
    }

    // 注册运行时的URI回调
    Desktop.getDesktop().setOpenURIHandler((event) -> {
        handleURI(event.getURI());
    });

    // 其他应用初始化逻辑
}

private static void handleURI(URI uri) {
    System.out.println("Received URI: " + uri);
    // 这里实现SSO参数处理逻辑
}

步骤3:修正Info.plist配置

  • 移除不必要的CFBundleDocumentTypes:该配置用于关联文档类型,和URI scheme处理无关,会干扰事件分发;
  • 确保CFBundleURLTypes配置正确(当前已符合要求);
  • 可选添加LSUIElement配置,确保应用能正确接收Apple Event:
<key>LSUIElement</key>
<false/>

步骤4:重新打包测试

  1. 重新编译C包装器,替换应用包中的主可执行文件;
  2. 更新Info.plist,移除多余的CFBundleDocumentTypes;
  3. 用open ourscheme://testing测试,查看应用日志输出;
  4. 测试应用已运行时的URI触发情况。

3. 备选方案:使用JDK自带jpackage工具

如果C包装器不是必须的,推荐用jpackage打包应用,它会自动处理macOS的URI注册、Apple Event传递等问题,无需手动编写C代码。示例命令:

jpackage --type app-image \
  --name "Our Product" \
  --input ./lib \
  --main-jar your-app.jar \
  --main-class com.yourcompany.MainClass \
  --icon ./icon.icns \
  --mac-package-identifier com.company.ourscheme \
  --mac-package-name "Our Product" \
  --arguments "custom-argument"

内容的提问来源于stack exchange,提问作者Fredrik Rafn Strandberg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 04:32:05