QCon 演讲火热征集中,快来分享技术实践与洞见! 了解详情
写点什么

此情可待成追忆:Java Mac 版的黄金时代

  • 2022-06-12
  • 本文字数:4494 字

    阅读完需:约 15 分钟

此情可待成追忆:Java Mac 版的黄金时代

在 App Store 诞生之前,Java 桌面应用就是 OS X 上的一流公民,它毁掉了所有的乐趣。

 

在本文中,我将以简略的校记,记述常被公众遗忘的 Mac Java 开发的黄金时代,那是在千禧年的头十年,从 2001 年首次发行 OS X 到 2011 年的 Mac App Store 的推出。HTML5 的问世也许扰乱了 Java 的企业阵营,但是那些开发 Mac 桌面应用的 Java 开发人员却没有受到任何影响。直到苹果宣布其 Mac App Store 的计划,“事情才变成现实”。

 

大约在 2006 年,我利用 Java 开发了一款工具,利用 OCR 将 PDF 文档转换成文本文档。起初,我只在 Mac 上发布,并在苹果网站的下载区进行推广(题外话:苹果的下载区是一个庞大的流量来源,远远超过了最终取代它的 Mac App Store)。彼时,Mac 仍然配备了 Java,因此,使用 Java 开发 Mac 应用并不存在“大小”的区别。它的外观和使用看起来就像原生应用一样,关键是在这个网络带宽还很有限的年代里,应用的大小非常小。

 

Windows 市场

 

我本来打算把这款应用移植到 Windows 上,但因为我是 Mac 的用户,我决定在解决这些问题之前先把它搁置一边。因为它是用 Java 写成的,所以要把它移植到 Windows 上并不是什么难事。我一直在使用一些 Mac 原生库进行图像增强,我需要为它们开发对 Windows 友好的替代品,并且我还得修改一些 UI 项目(比如,把“Quit”换成“Exit”,还有在文件关联上做了一些细微的修改)。

 

在将其移植到 Windows 的过程中,最难的就是为它开发安装程序。一开始,我用 Launch4J 为它创建了 Windows.exe 的启动程序。我将其作为一个 zip 压缩包发布,让用户将其拷贝到他们计算机上所需要的位置。但是,在常常被要求提供“适当的”安装程序后,我就用 Install4J 来创建了安装程序。因为这个“安装程序”本身就是 Java 应用,所以我使用 Launch4J 为这个安装程序创建了启动程序。

 

在 Windows 上的效果并不是很好,因为不完全是原生的,但是 Windows 用户不像 Mac 用户那样挑剔,所以它已经“足够好”。

 

当我第一次发布这款工具的 Windows 版本时,由于 Windows 市场远大于 Mac 市场,所以我预期销量会大幅增长。但我很失望地发现,尽管 Windows 的市场规模更大,但是其分布也更加广泛。在 Mac 上,你只要把你的应用放在苹果网站的下载区,你就可以获得几乎所有的用户。所有 Mac 用户在搜索软件时都会到这里来。

 

但是,在 Windows 上,并没有一个地方可以推广我的应用。有数以百计的下载站点,每个站点都充斥着和我的应用差不多的软件。在我的首次发布中,我将它提交给了几十个下载站点。我甚至可能为一个提交服务支付了费用,广告上写着他们会在数百个站点上自动发布你的应用。但是,在发布最初的几个版本之后,工作变得过于繁重,而带来的收益却微乎其微。Windows 版本对我的销量没有什么帮助。每销售一个 Windows 版本,我就能卖出 100 个 Mac 版本。所以,对于大多数版本,我把 Windows 版本发布在 CNET 下载(即 upload.com 和 download.com) 上,然后就不再发布了。

 

在随后的数年中,我逐渐建立起一种相当稳定的模式,每隔两三个星期就会进行一次小小的更新。我会在 MacUpdate 中发布 Mac 版本,在 CNET 中发布 Windows 版本。每一次更新都包含了 Bug 修复和新特性,这些新的发布都会吸引一些访问量,以维持下载量。

 

App Store:“我们不会为你这样的人服务”

 

在 2006 年至 2010 年期间,Java 在桌面计算机领域最大发展是:

 

  1. iPhone。这一点非常重要,因为它是另一个热门的新平台,而这个平台上面没有 Java。

  2. JavaFX。这很重要,因为它为 Java 的老化的 UI 工具包注入了急需的青春元素。

 

这两件事对我和我的小众工具都没有太大的影响,至少没有什么直接的影响。我的应用在 iPhone 上并没有多大的意义,因为这是为了处理你平时在桌面计算机上使用的文档。我的用户界面非常简洁,我不需要 JavaFX 提供的任何华丽的新图形。尽管如此,我还是饶有兴趣地关注着它们,因为我的雄心壮志早已超越了我那卑微的 OCR 应用,而现代图形和现代化平台对我来说实在太有吸引力了,以至于我无法忽视。

 

2010 年,苹果公布了 Mac App Store 的消息,引发了极大的轰动。苹果给了我一个许诺,但却在一次新闻发布会上将这个许诺从我身边扯走。他们宣称,他们将会把 Mac 应用放进新的应用商店。这是好的方面。不好的方面是,他们将不再推荐自己的 Java 发行版,而且,未来的 OSX 也不会包含 Java。此外,为了给 Java 致命一击,他们还在 App Store 的指导方针中明文规定,App Store 的应用不允许使用任何已经过时的库。

 

我并非一名律师,我生来就是一个乐观的人,因此,我还抱有一种想法,那就是,我还有一种方法可以把我的应用放到 App Store 里。我是说,公告并没有明确说 Java 应用不允许进入。它只是说 Java 现已被废弃,而且,应用不能再利用任何废弃的库。你必须将两者结合起来,才能得出这样的结论。这就好像是在拍一部电影,你不会亲眼看见那些坏人死去。“也许他从 50 楼摔下来的时候还活着!”很遗憾,苹果的技术支持部门证实了我的应用由于依赖 Java 而不能满足 App Store 要求。

 

Java 在 Mac 上的前途黯淡

 

在新闻发布会后的数个月中,人们对 Java 在 Mac 上的前途提出了疑问。Sun(现为 Oracle)一直在 Linux 和 Windows 上维护 Java,而苹果则一直维护和开发 Mac 版本。现在,苹果表示,他们将不会再这样做了。几个月后,Oracle 宣布他们将接手 Mac JDK 的开发,并将其纳入 OpenJDK 7 中,但是这还需要一段时间,并且在 2011 年 1 月 Mac App Store 的盛大开幕之前,它是不可能实现的。

 

替代 JVM

 

我从心底里感到,Mac App Store 是通往无限财富的钥匙,而就当时的情况来看,我已经被排斥在外了。那时候我还可以进入苹果网站的下载区,但是,从现实的角度来看,苹果有了 App Store 之后,还能坚持多久。我记得,App Store 刚上线没多久,苹果就把下载区给关掉了。

 

依我看,当时我有三个选择:

 

  1. 用 Objective-C 将我的应用重写为原生 Mac 应用。

  2. 等待 Oracle 新的 JDK7 Mac 版本,并尝试将其与我的应用程序捆绑。

  3. 使用替代的 JVM,并将其与我的 Mac 捆绑。

 

我是一个“不遗余力”的人,所以我基本上把这三个选择都试过了,但是最后还是选项 2(Oracle 的 JDK7)赢得了胜利。我只是错过了 Mac App Store 热棒的头一年。

 

在那一年里,我花费了大量的时间去测试其他 Java 虚拟机。我看到了所有有希望的事情,但是最令我记忆犹新的是 GCJ(The GNU Compiler for Java)、AvianIKVM + Mono。所有这些都存在着同样的局限性:没有 Swing 支持。如果我可以重构代码,让 UI 完全模块化,那么我就有可能在这些替代编译器中编译业务逻辑,并将其与另一个 UI 工具包(比如 SWT、QT 或 Cocoa)配对。

 

我发现 GCJ 的输出很难处理。我想不起具体的细节了,我只记得,我花了好几个星期的时间和它搏斗,最后把自己搞得遍体鳞伤,却找不到任何切实可行的办法。

 

我很喜欢使用 Avian,但它的运行时库没有包括所有的标准 JavaSE 类,所以它需要做太多的改动才能实用。(或许我就是太懒了,不愿意去做这些改动)。我用 Avian 做了几个测试,用 SWT 做用户界面,效果相当好。它们启动起来很迅速,而且可执行文件的大小也相当小,因此,虽然它并不适合这个项目,我还是在心里记下了它,以备将来之需。

 

到目前为止,我对另一种工具链的最佳体验是 IKVM+Mono。IKVM 是一个 Java 到 DotNet 的编译器,而 Mono 是 DotNet 的开源、跨平台版本。我能够将我的 Swing 代码剔除,并生成一个只有我的应用的业务逻辑的 jar,然后使用 IKVM 将其转换为一个 .dll 文件。Mono Mac 项目使用了 Cocoa 绑定,所以我能够在 interface builder 中建立一个 UI,然后用 C# 编写一些胶水代码,将其与我的应用的业务逻辑相连接。

 

我从来没有发布过我的应用的 Mono 版本,因为当它接近准备好的时候,Oracle 的 JDK7 就已经有了早期访问版本,这将允许我在发布时基本不做改动,从而大大降低长期的维护工作。

 

为 App Store 捆绑 App

 

JDK7 已经问世,唯一的困难就是捆绑原生应用。我所用的老式捆绑器和苹果的 Java 绑定,并没有将 JRE 捆绑到应用中,而是将它和系统中的 Java 安装绑定。在 JDK7 中,你需要将整个 JRE 捆绑到你的应用捆绑器中。这样你的应用会变得更大,但同时让你不再需要依赖过时的 API。这款应用将是独立的。

 

Oracle 提供了一款工具 javafxpackager,本应帮助你把你的应用捆绑成原生应用,但是却缺乏了 App Store 部署所需的某些重要特性。我只是凭着记忆工作,但是我还记得,除其他之外,在新的应用沙盒中,这款工具并没有起到很好的作用。所有 Mac App Store 的应用都要在其“沙盒”里运行。它们在 ~/Library/Containers/YOUR_APP_ID 目录下有自己的“小游乐场”,它们的所有文件都存储在那里。这只是需要一点额外的照顾和准备。(可这真是一件麻烦的事情!)

 

我正准备写自己的捆绑器,这时开源社区出现并拯救了我。一位名叫“InfiniteKind”的好心开发者开发或复刻了一个应用捆绑器,它可以与新的 JDK7 一起使用,并包括一些调整以满足苹果 App Store 的要求。谷歌搜索结果表明,这个应用捆绑器项目还在,而且在 README 文档里也还有我的一点贡献。

 

终于,在首次发布将近一年之后,我获准向 Mac App Store 提交我的应用。由于包含了捆绑的 Java 运行时,我的应用增加了 50 兆字节(压缩过的),但这并不重要,只要它能带来更多的销量。结果是,这并不会对销量造成什么实质性的影响。我猜想,如果没有这种渠道,那些从 App Store 购买的用户也会在我的网站上购买,因此,这其实就是在转移我的销售来源。App Store 的销售额每年都会有一定的增长,但同时网站的销售额会下降。现在,我的大部分销售都来自 App Store。

 

最后还是成功了……

 

对于我这种 Java 开发人员而言,在 Mac 上废弃 Java 的决定是一件很痛苦的事情。但是回顾过去,我觉得这样做是对的,也是无法避免的。假如他们当时没有“扣动扳机”,那么他们最后很有可能会被迫作出改变,而他们等得越久,就会越痛苦。

 

通过将 Mac 移植到标准的 OpenJDK 中,可以保证 Mac 用户可以跟上 Java 的发展。他们不会再受阻,等待一个不情愿的第三方管家来更新他们的版本。

 

尽管如此,在那个时候,Java 运行时必须和每个应用捆绑,这在那时是不必要的负担,现在仍然如此。史蒂夫·乔布斯曾说过:“没人会用 Java,它就是个巨大的锁链。”(Nobody uses Java anymore. It's this big heavyweight ball and chain.)由于 JRE 捆绑在每个 Java 应用中,所以每次下载应用更新时,用户都会收到提示。当然,在不同的应用中,也有一些共享这个“锁链”的方法。我对这个问题总是感到沮丧。这也是 jDeploy 开发的一个重要原因。

 

下次,我们将谈论“桌面 Java 的衰落与灭亡”(The Decline and Fall of Java on the Desktop)这一话题。具体来说,它是如何应对桌面上的 HTML5 巨无霸(JavaFX)的,以及它是如何悄悄地将自己定位为当今跨平台桌面开发的最佳平台的。

 

作者介绍:

 

Steve Hannah,jDeploy 作者。

 

原文链接:

 

https://jdeploy.substack.com/p/how-the-app-store-ended-a-golden?s=r

2022-06-12 14:416418

评论

发布
暂无评论
发现更多内容

工具 | 如何对 MySQL 进行 TPC-C 测试?

RadonDB

MySQL RadonDB

为什么零售业需要借助CRM系统蓬勃发展

低代码小观

企业管理 CRM 企业管理系统 CRM系统 企业管理软件

使用 Simple Replay 实用程序简化 Amazon Redshift RA3 迁移评估

亚马逊云科技 (Amazon Web Services)

mad

低代码实现探索(十四)工程化思想提高项目质量与可维护性

零道云-混合式低代码平台

万字详解 Spark 数据倾斜及解决方案

五分钟学大数据

spark 1月月更

中山市政务服务数据管理局党组书记叶永忠:积极构筑智慧联接新底座,打造中型智慧城市标杆

InfoQ_967a83c6d0d7

Linux云计算好学吗?Linux云计算运维学习资料 vim编辑器和恢复ext4下误删文件

学神来啦

workflow 之 Prefect 基本用法(qbit)

qbit

工作流 pipeline workflow 数据流

基于实例数据详解准确率和召回率

华为云开发者联盟

数据集 AUC 信息检索 准确率 召回率

效果提升28个点!基于领域预训练和对比学习SimCSE的语义检索

百度大脑

人工智能

前端开发之动态管理Nginx集群的方法

@零度

nginx 前端开发

开源demo| 智慧协同demo升级——协同更直观方便

anyRTC开发者

音视频 白板 智慧协同 开源demo 远程协助

斯图飞腾数据分析平台Stratifyd获评“2021大数据产业创新服务产品”

InfoQ_967a83c6d0d7

skywalking核心概念

淡泊明志、宁静致远

助力产教融合,夯实数据库产业人才基座!openGauss社区分委会正式成立

openGauss

【量化】量化交易入门系列6:量化交易学习书籍推荐(二)

恒生LIGHT云社区

量化策略 量化投资 量化交易 量化

面试官惊叹,好小子!你这多线程基础可以啊!

XiaoLin_Java

1月月更

在Spark Scala/Java应用中调用Python脚本,会么?

华为云开发者联盟

Python spark python脚本 Spark Scala Java应用

恒源云(GPUSHARE)_语音识别与语义处理领域之低资源机器翻译综述

恒源云

机器翻译 语音识别

【网络安全】你必须知道的几个网络安全概念

行云管家

运维 网络安全 防火墙 IT

风口上的“低代码”,是时候来系统学一学了!

博文视点Broadview

从四种时序数据库选型中脱颖而出,TDengine在工控领域边缘侧的应用

TDengine

数据库 大数据 tdengine 物联网

openGauss 助力邮储银行分布式新核心迈向智能运维时代

openGauss

3个重点,20个函数分析,浅析FFmpeg转码过程

奔着腾讯去

音视频 WebRTC ffmpeg RTMP RTSP

使用Amazon Redshift Simple Replay实用程序简化Amazon Redshift RA3迁移评估

亚马逊云科技 (Amazon Web Services)

mad

霸屏综艺,牵手明星,扩列神器皮皮APP的出圈始末

联营汇聚

MySQL高级特性篇教程

编程江湖

MySQL

低代码实现探索(十五)安全检查报告提高低代码数据安全性

零道云-混合式低代码平台

Mysql索引

zdd

MySQL

openGauss数据库源码解析系列文章——存储引擎源码解析(五)

openGauss

linux系统管理与自动化运维工具用哪款好?

行云管家

Linux 运维 IT运维 自动化运维

此情可待成追忆:Java Mac 版的黄金时代_语言 & 开发_Steve Hannah_InfoQ精选文章