长期以来,总是有网友给我留言或者私信关于输入法开发方面的问题,诸如零基础如何开始开发一款输入法、开发输入法需要多深厚的数学功底之类的问题。于是萌生了把这些回答汇集一篇文章的想法。 据说王小波也开发过输入法,据他说他用自己写的输入法写文章,体验还不错。当然了,那个时代的输入法无论是从功能上还是性能上,都无法和当下的输入法产品相比,但在那个时代,开发一款自己的输入法,绝对是一个很了不起的想法。而随着技术的进步,如软件库的丰富、硬件性能的爆发增长和开源项目的日益流行,以个人之力开发一款输入法不再像此前想象的那样困难。 说是开发一个输入法变简单了,但难度还是有的,即使技术上的门槛不再那么高了,但工作量还是不小的。那么下面,我们一起来看一看,当我们想要开发一款输入法时,我们都要做哪些方面的准备呢?

技术上的

  • 了解计算机的结构和工作原理;熟练掌握一门编程语言(Java/Swift/ObjC/C++等等都可以),并且最好是对底层语言像C语言一类,有一定的了解;清楚常用数据类型(byte/short/int/long等)所占用的字节数和表示范围;清楚常用的数据结构的使用方法和特点(队列/链表/包/栈/字典等);了解常用的设计模式及其原理; 这部分的知识是通用的,不针对任何平台,当然其实也不针对输入法开发,而是对于任何类型的应用开发而言,以上知识都是必须的,至少到了这一步,你已经不能算是零基础了。

  • 选择要为之开发输入法的平台,并了解该平台的技术特点; 很多时候,输入法开发的新手脑子里其实只有一个idea想要实现,而不知道应该怎么去实现,甚至也不知道应该先在哪个平台上去实现。就手机平台而言,目前可供选择的其实就两种,一个iOS,一个Android。对于第一次开发,或者说第一版开发而言,我的推荐必然是Android。 从经济的角度讲,搭建Android开发环境的成本要比iOS低很多,因为开发iOS你需要一台Mac,一台iPhone,如果你要发布你的输入法的话(当然,我想你不会只是做一个输入法自己玩玩),你还需要开发者证书,而这些都是要花钱买的。但如果你选择Android平台的话,是个电脑你就能开发,是部手机你就能调试,发布也不要向Google购买什么开发者证书,发给谁都可以安装。 从技术的角度讲,Android开发的技术资料更丰富,而且Android是开源的,有实在搞不清楚的地方,你甚至可以去查看Android的源码,这是iOS所不及的,而且就目前而言和我个人的经验之谈,Android的输入法框架要比iOS的输入法框架更成熟——坑少,对开发者更友好——限制少,这对初学者来说也意味着学习曲线没有那么陡峭。 其次,Android平台的用户群体更大,当你的输入法发布的时候,你的可能潜在用户也就更大,你有更大的机会在一开始起建立属于自己的用户群体。而且Android的应用发布周期更短(不需要审核),能够与你的用户建立起更高效的反馈迭代机制。 说了这么多,iOS平台难道一无是处吗?当然不是,如果你对你的idea非常自信,相信一旦做出来就可以从中获得盈利,那么iOS平台则更胜一筹。因为iOS平台的软件生态更良好,用户为软件付费的意识更强(普遍意义上)。

  • 理解主流的技术路线,并选择一条合适你的; 现在我们知道,开发一款手机应用其实早已不是只有原生技术可选了,不是说Android,我就只能用Java或者Kotlin,也不是说iOS,我就只能用Objective-C或者Swift。我们还可以有其他的选择,比如React Native、Qt、Flutter等等,这些是一般的应用目前可以选择的跨平台实现方案,那么输入法是否也有跨平台的实现方案呢?答案是有的,比如我正在使用的Xamarin,这是微软提供的一条跨平台开发的技术路线,我在这篇文章里介绍了我选择Xamarin的理由。据我理解,做输入法,Qt应该也是可以的,不过没有验证,而如React Native、Flutter之流,我的判断是应该不行,性能这一关可能过不去。 我提这些只是为了提醒你,除了原生技术路线,你其实还可以有其他的选择。当然如果你选择跨平台的方案,也就意味着你的开发曲线会变得更加陡峭,毕竟你要学习的东西更多了。但如果你想在后期把输入法扩展到其他平台上的话,你当下的选择将决定了你到时候需不需要重新一遍造轮子。 不过话又说回来,对于新手,我一般地建议还是最好选择原生的技术,那些“旁门左道”等你具备厚实的原生技术基础之后再去尝试是比较妥当的做法。根据我的经验,第一版乃至第二版输入法很大可能是要被推翻重写的,这个时候再重新选一个路线也为时未晚,至少我就是这么过来的。

  • 深入了解相应平台的输入法开发框架; 你需要了解在输入法在平台上是如何运行的,你要如何才能为他编写一个输入法,比如,Android上输入法是一个服务,而在iOS上,输入法是一个extension扩展;然后输入法的生命周期是什么样的,比如输入法弹出的时候会触发什么事件、收起的时候会触发什么事件、屏幕旋转的时候会触发什么事件、内存紧张的时候会触发什么事件等等; 同时你也要清楚,在这个平台上输入法能做什么,不能做什么,像iOS上,输入法的控件就无法显示到键盘的上方等等;还有输入法内存的限制有多大,iOS上目前大概是40m左右,Android可以跑到100m不被杀死(受品牌、机型和系统影响可能会有所差异)。这些信息对你决定是否要实现和如何去实现某些功能是至关重要的。 这里有我之前写的篇文章,仅供参考:Android与iOS输入法开发框架比较谈

  • 为你的输入法准备词库数据,量身编制好数据库格式。 所谓巧妇难为无米之炊,做输入法嘛,其实最核心的部分就是将用户的输入映射成相应的词组,没有数据,那一切也就无从谈起。假设你要做的一款拼音类型的输入法,那问题会简单很多,互联网是个大海洋,一般而言,网络上都可以找到你需要的数据,下载到这些数据之后,你可能还需要写一些程序来处理一下,将他们转换成你需要的格式。而如果你要做的是一款新型的形码方案,问题会棘手一些,你可能需要自己去编码,建议你找或者是做一个便于你编码的工具。 编制好合适的数据库格式非常重要。正确、合适的格式要在满足运行性能的前提下完成各式各样的词组检索操作,同时又不能占用太大的体积。编制一个正确的合适的格式大概有以下几条原则:

  1. 数据要素齐全;编制数据格式的时候,可以预留一列作为备用列;更改数据库的格式,增加新的内容都比较麻烦,尤其是在输入法发布之后。
  2. 数据应尽可能对齐;这样便于检索,不整齐的数据格式难于检索,也会无端地浪费性能和储存空间;
  3. 减少无用的冗余信息,在满足需要的前提下选择合适的储存类型;要预判这个列的信息未来会在哪个范围内波动,比如储存词条的类型,是自带的,还是用户造的,还是导入的,表示范围不可能成百上千,那么使用一个字节就足够了,没有必要更多。
  • 掌握Sqlite的使用方法,熟练地使用SQL语言,并了解相关的优化技巧。 有了数据之后,我们接下来要选择数据的载体。你可以自己编制一个数据文件格式,然后自己编写一套检索算法,又或者根据我的建议,选择Sqlite数据库,省心省力。 Sqlite是Android和iOS平台都自带有的数据库程序,关于Sqlite优点的资料应该是俯拾皆是,读者自己可以找一找,我这里就不赘述了。我建议选择Sqlite的理由很简单,就是你不需要再自己去实现一个词组的检索算法。要实现一个好的检索算法是相当困难的,这可能会占用你开发的大部分精力,而你劳神费力,最后可能会沮丧地发现,你做出来的效果还不如Sqlite提供的能力。所以这个选择非常关键。 而作为一名输入法开发者,对Sqlite数据库最大的担心莫过于其性能是否可以经受得起对用户流畅使用输入法这一要求的考验。根据我长期的使用体验,Sqlite的性能是够用的,特别是在硬件性能已经突飞猛进的今天,我甚至基于Sqlite实现了一个整句引擎都木有问题的啦。所以你可以大胆地选用Sqlite作为数据库程序,如果你确实不放心,你也可以选择设计一层与数据库实现无关的接口,在你认为Sqlite不能满足你需求的时候用其他实现替换他。如果数据检索成为了你输入法的性能瓶颈,那么很大可能是你的数据格式编制得不合理,无法发挥Sqlite的性能特点,也可能是你优化得不到位所致。只有在确定Sqlite已无优化潜力,而性能仍不达标的情况下再去考虑其他实现。但是在最开始,先让你的输入法能够运行起来才是第一要务,所以Sqlite绝对既是不二之选,也是不二之选。

  • 熟悉相应平台的图形绘制机制和事件处理机制 这一点对于任何应用来说都是必须的,但对于输入法来说,这一部分我们可能需要懂得更深入一些。 很少有一个应用,会像输入法一样,在一个狭小的空间内排放下如此之多的控件(就qwerty键盘而言,键盘上保守估计至少是30个按键,这仅仅是看得见的部分)。更多的控件就意味着更多的内存。令人苦恼的是,系统似乎并不会因此就对输入法更宽容,事实恰恰相反,所以我们只能在很有限的内存空间内做我们想做的事情。有些时候,为了达成目的,我们需要自己去实现一些控件的效果,甚至是完全由自己去绘制整个键盘(我就这么干过,但我奉劝各位,尽可能别走这条路)。而有些时候,输入法在图形上的开销太大会影响到使用的流畅度,所以我们也需要在优化界面流畅度上挖空心思。 如果你要实现的是一种基于非常规的复杂交互的输入法,比如说滑行输入的方式,那么我们就很难基于现成的事件监听器去实现这种交互,这个时候,我们就需要自己去截获这些事件,重新去分派他们或者处理他们。

  • 了解不同的字符集,了解如何显示emoji,了解繁简体的转换 Android和iOS现在都采用的Unicode字符集,大多数字符的显示都不成问题,但比如我们是在window上开发,然后在Android上显示,这个时候,我们就需要小心字符集不同可能带来的问题。而如果你要开发的输入法是小语种或者会涉及很生僻的生僻字,那么字符集问题都会很令人头疼。 现在的大多数输入法都会带有emoji的输入功能,但在编程的时候,emoji字符可不是以我们平时所看到的样子存在于文本中的,我们会以编码的形式存储他们,在需要显示和输入时再进行转换。这个开源项目大家可以参考一下emojione。 支持繁体对于部分中文输入法用户来说也是必不可少的,我们可以选择在数据库中存储繁简两种版本的字符,但我觉得更合理的做法是在需要的时候进行转换。OpenCC是繁简体转换方面做得非常出色的开源项目。

  • 了解接入第三方SDK的方法 现在语音输入已经很常见了,比如说你在用TNT的时候,emmmm,很酷哦。所以如果能给你的输入法接入语音输入的能力,绝对是一件锦上添花的事情,也可能是雪中送炭的事情(像岁寒输入法,有的用户打字一着急,就干脆用语音了,你们开心就好咯)。自己去开发一个语音输入引擎,实在是很不现实。市面上有不少大厂提供了语音输入的接口,我们可以通过接入这些接口来扩展我们输入法的能力,我所知道的有讯飞、百度和灵云。其中,灵云还提供手写识别的服务,感兴趣的可以了解一下。

  • 了解马尔科夫链和统计语言模型的相关理论,掌握图的相关算法 到目前为止,你已经可以开发出一款说得过去也说不过去的机械式检索输入法了。说得过去的部分是,这款输入法已经可以用了,如果是像五笔那一类型的形码输入法,其实基本上就这样啦。但说不去的部分是,如果是拼音输入法,你的输入法里还缺一个整句引擎。据我所知,这个部分目前没有任何公司提供接口可以调用,所以我们只好自己去实现。基于马尔科夫链的统计语言模型,我们就可以开发一款整句引擎出来,这里有我一篇之前写的文章:如何实现自己的一个智能整句引擎,仅供参考。这个整句引擎的本质是求解图的最短路径(开销最大部分其实是检索词组间的转移概率),所以掌握图的相关算法也是必须的,推荐阅读《算法》。 这里还有sunpinyin输入法开源项目,大家可以学习。

非技术上的

  • 你要有一个始终如一的理念。作为一个输入法开发者,我们既是开发者,也是设计师,我们要自己把握开发的尺度,决定什么要做,什么不要做。响应用户的呼声很重要,但遵从一个始终如一的理念同样重要;
  • 做一个基本的输入法出来其实不是多困难的事情,但是要做一个好用的输入法,可能需要付出非常巨大的努力,输入法的特点在于他几乎有无穷无尽的细节需要雕琢;
  • 开发输入法很大程度上是一件吃力不讨好的事情,如果你是出于学习的目的来开发一款输入法的,那也不错,如果不是,那你要做好血本无归的准备。就我而言,我做的第一版输入法,全世界都没人会用,只有我一个人会用;我做的第二版输入法,别人也会用了,但是没有人用;我做的第三版输入法,终于有人愿意用了。
  • 输入法改变不了世界,没有什么太特别的魔力。他只不过是一种用户黏性比较强的输入工具而已。

言尽于此,以上。