为 Firefox OS 构建 Firefox 浏览器

早在 2011 年 7 月 启动至 Gecko (B2G) 项目被 宣布 时,我就知道这是我想要贡献力量的事情。我之前已经研究了 基于浏览器的操作系统 的想法有一段时间了,但看起来 Mozilla 拥有的人才、技术和影响力能够构建真正具有颠覆性的东西。

当时 Mozilla 并没有积极招募人员来参与 B2G 项目,团队仍然只有四位联合创始人,该项目只不过是一个空的 GitHub 存储库。但是我在公告发布后的第二天就联系了他们,并在与 ChrisAndreasMike 通过 Skype 进行交谈并短暂访问硅谷之后,我不知何故说服他们接纳我(最初是作为承包商),以便我能够全职参与该项目。

一个由 Web 技术构建的 Web 浏览器

在我第一天上班时,Chris Jones 对我说:“下一个最高优先级的项目是一个非常基本的 Web 浏览器,基本上只是一个 URL 地址栏和后退按钮。”

Chris 和他的微型浏览器,台北,2011 年 12 月

团队正在创建一个名为“Gaia”的原型智能手机用户界面,完全使用 Web 技术构建。部分是为了证明它可以做到,部分是为了找出 Web 平台中导致构建困难的漏洞,并用新的 Web API 填补这些漏洞。我被要求参与浏览器应用程序、相机应用程序和图库应用程序的第一个原型开发,以帮助找出一些漏洞。

您可能想知道为什么基于浏览器的操作系统还需要浏览器应用程序,但这个原型的思路是,如果其他智能手机平台都有一个浏览器应用程序,那么 B2G 也需要一个。

桌面版 Firefox 的用户界面是用具有高度特权的“chrome”代码使用 XUL 标记语言编写的。在 B2G 上,它需要用“content”编写,并且只能使用 HTML、CSS 和 JavaScript,就像所有其他应用程序一样。这将带来一些有趣的挑战。

起初,有一个<iframe>

一切始于一个简单的 iframe、一个用于 URL 地址栏的文本输入和一个“Go”按钮,事实上,您可以看到第一个提交 在这里。当您点击“Go”按钮时,它会将 iframe 的 src 属性设置为文本输入的内容,这会导致 iframe 加载该 URL 上的网页。

第一个提交,2011 年 11 月

尝试使用 iframe 构建 Web 浏览器的第一个问题是,JavaScript 中的 同源策略 阻止您访问有关其内部发生情况的几乎任何信息,如果内容来自与浏览器本身不同的来源。特别是,无法访问 contentWindow 属性以及它提供的所有信息。该策略存在是有充分理由的,因此为了构建一个功能齐全的 Web 浏览器,我们必须想办法让特权 Web 应用程序安全地在这个跨源边界上打孔,以获取足够的信息来完成其工作,但不会造成严重的安全性漏洞或损害用户的隐私。

我们很快遇到的另一个问题是,许多网页作者会不遗余力地阻止他们的网站加载到 iframe 中,以防止 网络钓鱼 攻击。Web 服务器可以发送一个 X-Frame-Options HTTP 响应标头,指示用户代理根本不呈现内容,并且还有一些“framebusting”技术,其中网站会主动尝试从 iframe 中跳出并在父框架中加载自身。

很快很明显,如果我们不发展 Web 技术本身,我们就无法使用 Web 技术构建 Web 浏览器。

浏览器 API

我在 2011 年 12 月在台北举行的第一次 B2G 工作周上遇到了 Justin Lebar。他的任务是修改 Gecko,使 Boot to Gecko 上的浏览器应用程序成为可能。对我来说,Gecko 是(并且在很大程度上仍然是)一个巨大的魔法咒语黑盒,它可以接收我编写的代码,并将其转换为屏幕上的动态图像。我需要一位掌握其中一些咒语的巫师,包括一个名为 Docshell 的特别强大的咒语,只有最熟练的巫师才敢窥探其中。

Justin 在台北举行的第一次 B2G 工作周上,2011 年 12 月

当我告诉 Justin 我需要什么时,他发出了类似于你把你的车送到维修店进行你认为很简单但最终却要花费一辆新车价格的维修时,机械师发出的那种声音。Justin 比我更了解需要什么,但我认为我们俩都没有意识到手头任务的全部规模。

通过在 Gecko 中的 HTML iframe 元素中添加一个简单的布尔值“mozbrowser”属性,浏览器 API 诞生了。我尝试向浏览器应用程序添加功能,并且每次发现当前 Web 技术无法实现某些功能时,我都会回到 Justin 那里让他施展新的魔法咒语。

我们可以采取更简单的方法来构建浏览器应用程序。我们可以添加一种机制,允许浏览器将脚本注入 iframe 并与其中的内容自由通信,但我们希望提供一个任何人都可以使用来构建自己的浏览器应用程序的安全 API,而这种方法风险太大。因此,我们改为在 DOM 中构建了一个显式特权 API,以创建一种新类型的 iframe,它有一天可能会成为 新的标准 HTML 标签

保持 Web 的包含性

我们做的第一件事是试图欺骗加载到 iframe 中的网页,让它们认为实际上并没有在 iframe 中。起初,我们有一个粗略的解决方案,它只是忽略了白名单域中具有 mozbrowser 属性的 iframe 的 X-Frame-Options 标头。那时我们发现有些网站在跳出 iframe 方面非常聪明。最后,我们不得不采取其他措施,例如确保 window.top 指向 iframe 而不是其父级,这样网站就无法检测到它有一个父级,并且最终还在其自己的系统进程中运行每个浏览器选项卡,以完全隔离它们。

一旦我们控制住了 Web 这个“动物”,我们就需要戳几个通气孔让它呼吸。我们需要以 事件 的形式将一些信息从 iframe 中释放出来:当网页的位置、标题或图标更改时(locationchange、titlechange 和 iconchange);当页面开始和完成加载时(loadstart、loadend);以及当当前加载页面的安全特性更改时(securitychange)。所有这些都允许我们保持地址栏和标题栏的最新状态并显示进度指示器。

浏览器应用程序需要能够 导航 iframe,告诉它 goBack()、goForward()、stop() 和 reload()。我们还需要能够明确地请求诸如会话历史记录的特性(getCanGoBack()、getCanGoForward())之类的信息,以确定要显示哪些导航按钮。

有了这些基础,就可以构建一个简单的功能性浏览器应用程序了。

原型

Gaia 项目的第一位 UX 设计师是 Josh Carpenter。在 2012 年 2 月世界移动通信大会前一周在巴黎举行的一个密集的工作周中,Josh 创建了所有基本智能手机功能(包括一个简单的浏览器)的 UI 模型,我们根据这些设计构建了一个原型。

Josh 和我在巴黎喝啤酒时一起策划。

 

原型浏览器应用程序可以导航 Web 内容,将其包含在内并显示有关正在查看的内容的基本信息。这将是当年在巴塞罗那世界移动通信大会上展示的版本。

世界移动通信大会上的简单浏览器演示,2012 年 2 月

组建团队

在 2012 年 5 月在高通位于圣地亚哥的办公室举行的一个工作周中,我能够演示一个稍微高级一点的基本浏览器 Web 应用程序,它在桌面上运行在 Firefox 中。但它仍然非常基础。我们需要一个团队开始构建足够好的东西,以便我们可以在真实的设备上发布它。

“浏览器盗梦空间”,2012 年 5 月圣地亚哥

圣地亚哥也是我第一次遇到 Dale Harvey 的地方,他是一位勇敢的苏格兰人,加入了 Gaia 项目的团队。他首先帮助处理浏览器应用程序。

Dale 在 2012 年 5 月圣地亚哥加入团队。

Dale 从事的第一项工作之一是在浏览器中创建多个选项卡,甚至向浏览器 API 添加了一个 截图咒语 以显示浏览器选项卡的缩略图(我告诉过你他很勇敢)。

到那时,我们还开始借用 Firefox 团队中一位才华横溢的设计师 Larissa Co 来处理交互设计,以及前 RIM 员工 Patryk Adamczyk 来处理 B2G 上浏览器的视觉设计。那时它开始更像一个 Firefox 浏览器了。

早期 UI 模型,2012 年 7 月

弹出内容

网页喜欢弹出内容。首先,它们喜欢使用 alert()prompt()confirm() 与您交互。有时它们喜欢 open() 一个新的浏览器窗口(并 close() 它们),在 _blank 窗口中打开链接,向您询问 密码,询问您执行某些操作的 权限,要求您从菜单中 选择 一个选项,打开上下文菜单或确认重新发送表单内容。

alert(),1.0 版

所有这些都需要浏览器 API 中有新的 事件,这意味着 Justin 需要施放更多咒语。

滚动、平移和缩放

在 Web 设备上移动网页的方式与在桌面上略有不同。它不使用鼠标上的滚动条或滚轮,而是使用触摸输入和一个称为异步平移和缩放的系统,允许用户通过拖动和滚动网页来对其进行平移,使用“动量滚动”,感觉就像它有一些物理效果一样。

动量滚动的第一个实现是由法国人和 Gaia 领导者 Vivien Nicolas 使用 JavaScript 编写的,专门用于 Gaia,但它后来将在 Gecko 中以跨平台的方式编写,以统一 B2G 和 Android 上使用的代码。

需要正确处理的一个比较棘手的交互是,我们希望地址栏在您向下滚动页面时隐藏,以便为内容腾出更多空间,然后在您滚动回页面顶部时再次显示。

这需要添加 asyncscroll 事件,这些事件直接进入异步平移和缩放代码,以便浏览器不仅知道用户何时直接操作页面,还知道它基于物理学异步滚动了多少,独立于用户的交互。

存储内容

Firefox 最受欢迎的功能之一是“Awesomebar”,它是一个结合了地址栏、搜索栏(在移动设备上是标题栏)的功能,可以让您快速访问您要查找的内容。您键入几个字符,就会立即开始看到来自浏览历史记录的匹配网页,并根据 “频率”算法 进行排名。

在桌面和 Android 上,所有这些数据都存储在“Places”数据库中,作为特权“chrome”代码的一部分。为了在 B2G 中实现此功能,我们需要使用 Web 的本地存储功能,为此我们选择了 IndexedDB。我们在 IndexedDB 中构建了一个 Places 数据库,它将存储用户在 Web 上访问的所有“位置”,包括其 URL、标题和图标,以及存储用户访问该页面的所有时间。它还将用于存储用户的书签,并根据 “频率” 对热门网站进行排名。

Awesomebar,1.0 版

清除内容

当您在 Web 上浏览时,Gecko 还会存储有关您访问过位置的大量数据。这可能是 cookie、脱机页面、localStorage、IndexedDB 数据库以及各种其他数据片段。Firefox 浏览器提供了一种方法来清除所有这些数据,因此需要向浏览器 API 添加方法,以允许从 B2G 中的浏览器设置中清除这些数据。

浏览器设置,1.0 版

处理崩溃

有时网页会导致浏览器崩溃。在 B2G 中,每个 Web 应用程序和每个浏览器选项卡都在其自己的系统进程中运行,因此如果发生最糟糕的情况,只会导致该窗口/选项卡崩溃。事实上,由于 B2G 最初目标的低端智能手机的内存限制,有时系统会故意终止后台应用程序或浏览器选项卡以节省内存。浏览器应用程序需要在发生这种情况时得到通知,并且需要能够无缝恢复,因此在大多数情况下,用户甚至不会意识到某个进程被终止了。为此目的,向浏览器 API 添加了事件。

崩溃的选项卡,1.0 版

与其他应用程序通信

移动浏览器的常见用例包括用户希望使用其他应用(如社交网络工具)分享 URL,或者其他应用希望使用浏览器查看 URL。

B2G 为此实现了 Web 活动,为 Web 添加了一种功能,使应用能够以与应用无关的方式相互交互。例如,用户可以点击浏览器应用中的分享按钮,B2G 将触发“分享 URL”Web 活动,然后任何已注册处理此类 Web 活动的已安装应用都可以处理该活动。

分享 Web 活动,版本 1.2

离线工作

尽管 B2G 和 Gaia 是基于 Web 构建的,但所有内置的 Gaia 应用都必须能够在网络连接不可用或不稳定时离线运行,以便用户仍然可以拨打电话、拍照和听音乐等。起初,我们开始使用 AppCache 来实现此目的,这是 Web 首次尝试使 Web 应用能够离线工作。不幸的是,我们很快遇到了该技术许多常见的 问题和限制,发现它无法满足我们所有的需求。

为了按时发布 B2G 1.0 版本,我们被迫实施“打包应用”来满足内置 Gaia 应用的所有离线和安全需求。打包应用解决了我们的问题,但它们并非真正的 Web 应用,因为它们在互联网上没有真正的 URL,并且 标准化 它们的尝试并没有获得太多关注。打包应用最初被视为一种临时解决方案,我们正在努力为 Web 添加新的功能,例如 ServiceWorkers标准化的托管包清单,以便最终不再需要专有的打包应用来获得完整的离线体验。

离线,版本 1.4

润色

最后,我们对浏览器应用 UI 进行了大量的润色,使其使用起来干净流畅,充分利用了硬件加速的 CSS 动画,并加入了一些 Firefox 式的交互和视觉设计,使 Firefox 浏览器家族中最年轻的成员与其他平台上的兄弟姐妹保持一致。

发布 1.0

2013 年 1 月,在德国电信主办的柏林史诗级工作周中,整个 B2G 团队(包括来自多个竞争移动网络和设备制造商的工程师)齐聚一堂,共同努力发布 B2G 1.0,以便及时在 2 月巴塞罗那的世界移动通信大会上进行演示。该团队通过在一周内修复了令人难以置信的 200 个错误,朝着这个目标冲刺。

1.0 版本团队,柏林工作周,2013 年 1 月

在本周的最后几分钟,Andreas Gal 兴奋地宣布“Zarro Gaia Boogs”,标志着 Gaia 1.0 版本已完成,其余的 B2G 将在周末很快推出。大约 18 个月内,一个跨越多个组织的专门团队完全公开合作,将一个空的 GitHub 存储库变成了一个功能齐全的移动操作系统,该系统后来作为 Firefox OS 1.0.1 发布到真实设备上。

Zarro Gaia Boogs,2013 年 1 月

浏览器应用 v1.0

因此,在 2012 年的世界移动通信大会上,我们带着一个原型和一个将商用设备推向市场的承诺出席了会议,我们能够在 2013 年重返大会,兑现了这一承诺,通过在多个移动网络上推出多个设备,全面推出了“Firefox OS”品牌,此次发布确实抢走了全球最大移动会议的风头。Firefox OS 已经到来。

世界移动通信大会,巴塞罗那,2013 年 2 月

1.x

Firefox OS 1.1 紧随其后,到我们开始开发 1.2 版本时,项目规模已经显著增长。我们重组为专注于产品领域的自主敏捷团队,浏览器应用就是其中之一。这意味着我们现在拥有一个专门的团队,其中包括设计师、工程师、测试工程师、产品经理和项目经理。

浏览器团队,伦敦工作周,2013 年 7 月

Firefox OS 采用了类似 Firefox 的快速发布“火车模型”开发模式,每 12 周发布一个新版本。我们快速添加了新功能并致力于提高性能,以充分利用我们在新兴市场推出的低端硬件。

浏览器应用 v1.4

“海达”

Firefox OS 1.0 版本主要是在证明我们能够构建其他智能手机上已有的东西,但完全使用开放的 Web 技术。其中包括一个浏览器应用。

一旦我们证明了这一点,并将真正的设备摆上货架推向市场,就该考虑如何让 Firefox OS 作为产品在未来脱颖而出。我们希望构建一些东西,这些东西不仅模仿已完成的工作,而且利用 Web 的独特优势来构建符合 Mozilla DNA 的东西,这是体验 Web 的最佳方式,也是 HTML5 应得的平台。

以下是 2011 年年底项目开始初期我创建的一个模型,甚至在我们拥有 UX 团队之前。我之前提到过,Awesomebar 是 Firefox 浏览器中 Firefox 体验的核心部分。我当时的提议是构建一个系统范围的 Awesomebar,它可以搜索整个设备,包括你的应用及其内容,并且可以在操作系统的任何位置访问。

系统范围的 Awesomebar 的早期模型,2011 年 12 月

当时,这被认为对于 1.0 版本来说过于激进,我们的重点确实需要放在构建移动操作系统的 Web 技术创新上,而不是用户体验。我们将采取更保守的用户界面设计方法,构建一个与我们为 Android 构建的浏览器应用非常相似的应用。

实际上,这意味着我们在 Firefox OS 中实际上构建了两个浏览器。一个是管理“网站”世界的浏览器应用,另一个是系统应用中的窗口管理器,管理“Web 应用”的世界。

实际上,在 Web 上,“Web 应用”和“网站”之间的区别并不那么明显——它们都存在于用户体验的长链条上,中间的界限非常模糊。

2013 年 3 月,Firefox OS 1.0 发布后,Josh Carpenter 将我与 UX 团队成员 Gordon Brander 联系起来,Gordon 当时的想法与我类似。事实上,Gordon 既是工程师又是设计师,他已经用 JavaScript 编写了一个基本的原型。

Gordon 的 Rocketbar 原型,2013 年 3 月

我和 Gordon 开始每周见面讨论他的概念,当时代号为“Rocketbar”,但这只是一个有少数人感兴趣的副项目。

2013 年 4 月,UX 团队在伦敦举行了一次峰会,他们聚在一起讨论 Firefox OS 用户体验的未来方向。我很幸运地受邀不仅旁观,而且参与了这个过程,Josh 渴望保持设计和工程之间密切的合作关系。

我们集思广益,探讨了 Web 体验的独特之处,以及我们如何创造一个发挥这些优势的独特用户体验。一个重点是“流动”,我们通过遵循超链接在 Web 上漫游的方式。Web 不是一个由各个应用组成的世界,它们之间有明确的界限,而是一种从一个网站到另一个网站的冲浪体验,在内容中流动。

头脑风暴会议,伦敦,2013 年 4 月

在接下来的几周里,UX 团队将为一个概念(最终代号为“海达”)创建一些早期设计,该概念将模糊 Web 应用和网站之间的界限,并创造一种像 Web 一样流动的独特用户体验。这最终将不仅包括“Rocketbar”(它可以在整个操作系统中访问,并无缝适应不同类型的 Web 内容),还包括“表单”(它将单页 Web 应用拆分为多个页面,你可以使用直观的边缘手势在这些页面之间滑动)。它最终还将包括一个基于实时应用的内容模型,你可以浏览这些应用、使用这些应用,然后选择将其添加为书签,而不是必须从中央应用商店安装才能使用的整体应用。

2013 年 6 月,一小群设计师和工程师在巴黎会面,开发了一个“海达”的临时原型,以快速迭代一些更激进的概念并进行用户测试。

海达原型设计,巴黎,2013 年 6 月

Josh 和 Gordon 高度协调地工作,巴黎,2013 年 6 月

工作中的奇才,巴黎,2013 年 6 月

2.x 及未来

快进到今天,浏览器团队已并入“系统前端”团队。“海达”原型设计和用户测试的结果正逐渐融入到 Firefox OS 的主要产品中。这不会一蹴而就,而是在我们迭代和学习的过程中逐步实现。

在 Firefox OS 2.0 版本中,1.x 版本的主屏幕搜索功能将被一个新的搜索体验所取代,该体验与 Kevin Grandon 实施的新主屏幕一起开发,这将为“Rocketbar”奠定基础。在 2.1 版本中,我们的目标是将浏览器应用完全合并到系统应用中,以便浏览器选项卡成为任务管理器中应用旁边的“表单”,并且“Rocketbar”可以在操作系统的任何位置访问。“Rocketbar”将适应不同类型的 Web 内容,并在不使用时缩小到状态栏。边缘手势允许你在 Web 应用和浏览器窗口之间滑动,最终应用将能够生成多个表单。

Rocketbar 在展开和折叠状态下的 UI 模型,2014 年 7 月

与此同时,我们看到了围绕 清单Web 视图 的 Web 标准的演变,以及围绕定义 “应用”范围 的持续讨论。

总结

Firefox OS 1.x 版本是使用 Web 技术构建的,但在安装和使用应用以及浏览 Web 方面,其用户体验与其他移动平台非常相似。展望未来,我认为你会看到 Web 的 DNA 体现到用户界面中,形成统一的体验,打破 Web 应用和网站之间的界限,让你能够在这两者之间自由流动。

Firefox OS 是一个完全在 开放 环境下开发的开源项目。如果你有兴趣为 Gaia 做出贡献,请查看 MDN 上的“开发 Gaia”页面。如果你有兴趣创建自己的 HTML5 应用以在 Firefox OS 上运行,请查看“应用中心”。

关于 Ben Francis

前 Mozilla 软件工程师。W3C Web 应用和物联网受邀专家。

更多 Ben Francis 的文章……

关于 Robert Nyman [荣誉编辑]

Mozilla Hacks 的技术布道师和编辑。发表关于 HTML5、JavaScript 和开放 Web 的演讲和博客。Robert 是 HTML5 和开放 Web 的坚定支持者,自 1999 年以来一直从事 Web 前端开发工作——在瑞典和纽约市。他还在 http://robertnyman.com 上定期发表博客,并且喜欢旅行和结识新朋友。

更多 Robert Nyman [荣誉编辑] 的文章……


19 条评论

  1. M. Ahmad Zafar

    我刚刚获得了 Flame 参考手机。如果我对用户体验有建议,应该联系谁?此外,FirefoxOS 有没有类似 Stack Overflow 的网站?

    2014 年 8 月 7 日 08:50

    1. Robert Nyman [编辑]

      关于建议,我们接受 GitHub 上的拉取请求,或者 Firefox OS 帮助论坛 可能是不错的选择。对于 Stack Overflow,是的,有一个!请访问 Stack Overflow 上的 firefox-os 标签

      2014 年 8 月 7 日 09:41

    2. Steve Glick

      有一个 Stack Exchange 提议要创建一个 FirefoxOS 网站,但它还需要一段时间才能启动。 https://area51.stackexchange.com/proposals/59192/firefox-os

      2014年8月13日 14:39

  2. Akash Agrawal

    这篇文章写得太棒了!

    2014年8月7日 11:24

    1. Robert Nyman [编辑]

      谢谢,很高兴你喜欢!

      2014年8月8日 01:10

  3. Adam

    很棒的项目!但是,我们仍然期待扩展或至少是GreaseMonkey用户脚本。

    2014年8月7日 15:26

    1. Robert Nyman [编辑]

      谢谢!我们拭目以待。你也可以在Bug 923897中关注进展。

      2014年8月8日 01:11

  4. Abin Abraham

    我有一些建议/想法可以改进Firefox OS中的Firefox浏览器。我应该把它们发送给谁?

    2014年8月7日 19:33

    1. Robert Nyman [编辑]

      上面评论中所述,请尝试这些渠道。

      2014年8月8日 01:08

  5. Vincent

    我想知道试图通过跳出iframe来处理网络钓鱼的网站如何响应webview……

    2014年8月8日 05:49

    1. Ben Francis

      如文章中所述,我们对浏览器标签使用了一种特殊的iframe类型,它们在单独的系统进程中运行,网站无法跳出(如果它们可以跳出,则可以接管浏览器应用程序本身的窗口)。

      创建这些特殊iframe或“webview”需要“浏览器”权限,该权限仅对特权应用程序可用。所有其他iframe将按往常一样运行,并且可以从中进行framebust。

      2014年8月11日 10:09

  6. Jeffrey

    “在2.1版本中,我们的目标是将浏览器应用程序完全合并到系统应用程序中,以便浏览器标签成为任务管理器中应用程序旁边的“sheet”,并且“Rocketbar”可以在操作系统的任何位置访问。”

    如果我没记错的话,Android L有这个功能。所以这并不会让Firefox OS与众不同。希望有更多Android不容易实现的雄心勃勃的想法,Firefox OS将探索这些想法,当然也会提升用户体验。

    2014年8月8日 06:26

    1. Ben Francis

      我很高兴看到Web在早期版本的Android L任务切换器中成为更重要的角色!据我所知,Firefox OS确实有一些其他独特的功能,例如“Rocketbar”可以从状态栏系统范围内访问,而不是包含在浏览器应用程序内部,以及使用边缘手势在应用程序和浏览器窗口之间切换。

      Chrome OS和Android确实有越来越靠近的迹象,我们当然欢迎其他平台拥抱Web。事实上,这对我们的使命至关重要!

      2014年8月11日 10:14

  7. René Dudfield

    项目不得不跳过FirefoxOS,因为它缺少后台模式。尽管是为phonegap编写的,但FirefoxOS缺少此功能,因此无法移植任何应用程序。

    当应用程序在人们的口袋里时,这对移动应用程序非常有用。

    对于其他流行的功能,不仅要查看基本的Cordova/phonegap插件,还要查看其他流行的插件。

    后台模式是我对真正应用程序最怀念的主要功能。

    干杯!

    2014年8月8日 11:42

  8. Vangelis Misirlis

    关于我们的建议,我们可以使用Bugzilla吗?

    谢谢。

    2014年8月9日 04:32

    1. Robert Nyman [编辑]

      你可以尝试,但主要我想说的是,Bugzilla是关于处理错误/缺少功能的,而这听起来更像是普通的建议,所以上面提到的渠道至少是一个更好的起点。

      2014年8月11日 03:12

  9. Pavel Ivanov

    你o/ :)

    2014年8月10日 13:52

  10. Albert

    非常棒的摘要。期待未来的2.x更新,并期待下一款Fairphone能够使用FOS :)

    干得好!

    2014年8月13日 03:29

    1. Robert Nyman [编辑]

      谢谢,很高兴你喜欢这篇文章!

      2014年8月13日 03:35

本文评论已关闭。