長期以來,總是有網(wǎng)友給我留言或者私信關(guān)于輸入法開發(fā)方面的問題,諸如零基礎(chǔ)如何開始開發(fā)一款輸入法、開發(fā)輸入法需要多深厚的數(shù)學(xué)功底之類的問題。于是萌生了把這些回答匯集一篇文章的想法。
據(jù)說王小波也開發(fā)過輸入法,據(jù)他說他用自己寫的輸入法寫文章,體驗還不錯。當(dāng)然了,那個時代的輸入法無論是從功能上還是性能上,都無法和當(dāng)下的輸入法產(chǎn)品相比,但在那個時代,開發(fā)一款自己的輸入法,絕對是一個很了不起的想法。而隨著技術(shù)的進步,如軟件庫的豐富、硬件性能的爆發(fā)增長和開源項目的日益流行,以個人之力開發(fā)一款輸入法不再像此前想象的那樣困難。
說是開發(fā)一個輸入法變簡單了,但難度還是有的,即使技術(shù)上的門檻不再那么高了,但工作量還是不小的。那么下面,我們一起來看一看,當(dāng)我們想要開發(fā)一款輸入法時,我們都要做哪些方面的準(zhǔn)備呢?
技術(shù)上的
了解計算機的結(jié)構(gòu)和工作原理;熟練掌握一門編程語言(Java/Swift/ObjC/C++等等都可以),并且最好是對底層語言像C語言一類,有一定的了解;清楚常用數(shù)據(jù)類型(byte/short/int/long等)所占用的字節(jié)數(shù)和表示范圍;清楚常用的數(shù)據(jù)結(jié)構(gòu)的使用方法和特點(隊列/鏈表/包/棧/字典等);了解常用的設(shè)計模式及其原理;
這部分的知識是通用的,不針對任何平臺,當(dāng)然其實也不針對輸入法開發(fā),而是對于任何類型的應(yīng)用開發(fā)而言,以上知識都是必須的,至少到了這一步,你已經(jīng)不能算是零基礎(chǔ)了。選擇要為之開發(fā)輸入法的平臺,并了解該平臺的技術(shù)特點;
很多時候,輸入法開發(fā)的新手腦子里其實只有一個idea想要實現(xiàn),而不知道應(yīng)該怎么去實現(xiàn),甚至也不知道應(yīng)該先在哪個平臺上去實現(xiàn)。就手機平臺而言,目前可供選擇的其實就兩種,一個iOS,一個Android。對于第一次開發(fā),或者說第一版開發(fā)而言,我的推薦必然是Android。
從經(jīng)濟的角度講,搭建Android開發(fā)環(huán)境的成本要比iOS低很多,因為開發(fā)iOS你需要一臺Mac,一臺iPhone,如果你要發(fā)布你的輸入法的話(當(dāng)然,我想你不會只是做一個輸入法自己玩玩),你還需要開發(fā)者證書,而這些都是要花錢買的。但如果你選擇Android平臺的話,是個電腦你就能開發(fā),是部手機你就能調(diào)試,發(fā)布也不要向Google購買什么開發(fā)者證書,發(fā)給誰都可以安裝。
從技術(shù)的角度講,Android開發(fā)的技術(shù)資料更豐富,而且Android是開源的,有實在搞不清楚的地方,你甚至可以去查看Android的源碼,這是iOS所不及的,而且就目前而言和我個人的經(jīng)驗之談,Android的輸入法框架要比iOS的輸入法框架更成熟——坑少,對開發(fā)者更友好——限制少,這對初學(xué)者來說也意味著學(xué)習(xí)曲線沒有那么陡峭。
其次,Android平臺的用戶群體更大,當(dāng)你的輸入法發(fā)布的時候,你的可能潛在用戶也就更大,你有更大的機會在一開始起建立屬于自己的用戶群體。而且Android的應(yīng)用發(fā)布周期更短(不需要審核),能夠與你的用戶建立起更高效的反饋迭代機制。
說了這么多,iOS平臺難道一無是處嗎?當(dāng)然不是,如果你對你的idea非常自信,相信一旦做出來就可以從中獲得盈利,那么iOS平臺則更勝一籌。因為iOS平臺的軟件生態(tài)更良好,用戶為軟件付費的意識更強(普遍意義上)。理解主流的技術(shù)路線,并選擇一條合適你的;
現(xiàn)在我們知道,開發(fā)一款手機應(yīng)用其實早已不是只有原生技術(shù)可選了,不是說Android,我就只能用Java或者Kotlin,也不是說iOS,我就只能用Objective-C或者Swift。我們還可以有其他的選擇,比如React Native、Qt、Flutter等等,這些是一般的應(yīng)用目前可以選擇的跨平臺實現(xiàn)方案,那么輸入法是否也有跨平臺的實現(xiàn)方案呢?答案是有的,比如我正在使用的Xamarin,這是微軟提供的一條跨平臺開發(fā)的技術(shù)路線,我在這篇文章里介紹了我選擇Xamarin的理由。據(jù)我理解,做輸入法,Qt應(yīng)該也是可以的,不過沒有驗證,而如React Native、Flutter之流,我的判斷是應(yīng)該不行,性能這一關(guān)可能過不去。
我提這些只是為了提醒你,除了原生技術(shù)路線,你其實還可以有其他的選擇。當(dāng)然如果你選擇跨平臺的方案,也就意味著你的開發(fā)曲線會變得更加陡峭,畢竟你要學(xué)習(xí)的東西更多了。但如果你想在后期把輸入法擴展到其他平臺上的話,你當(dāng)下的選擇將決定了你到時候需不需要重新一遍造輪子。
不過話又說回來,對于新手,我一般地建議還是最好選擇原生的技術(shù),那些“旁門左道”等你具備厚實的原生技術(shù)基礎(chǔ)之后再去嘗試是比較妥當(dāng)?shù)淖龇ā8鶕?jù)我的經(jīng)驗,第一版乃至第二版輸入法很大可能是要被推翻重寫的,這個時候再重新選一個路線也為時未晚,至少我就是這么過來的。深入了解相應(yīng)平臺的輸入法開發(fā)框架;
你需要了解在輸入法在平臺上是如何運行的,你要如何才能為他編寫一個輸入法,比如,Android上輸入法是一個服務(wù),而在iOS上,輸入法是一個extension擴展;然后輸入法的生命周期是什么樣的,比如輸入法彈出的時候會觸發(fā)什么事件、收起的時候會觸發(fā)什么事件、屏幕旋轉(zhuǎn)的時候會觸發(fā)什么事件、內(nèi)存緊張的時候會觸發(fā)什么事件等等;
同時你也要清楚,在這個平臺上輸入法能做什么,不能做什么,像iOS上,輸入法的控件就無法顯示到鍵盤的上方等等;還有輸入法內(nèi)存的限制有多大,iOS上目前大概是40m左右,Android可以跑到100m不被殺死(受品牌、機型和系統(tǒng)影響可能會有所差異)。這些信息對你決定是否要實現(xiàn)和如何去實現(xiàn)某些功能是至關(guān)重要的。
這里有我之前寫的篇文章,僅供參考:Android與iOS輸入法開發(fā)框架比較談為你的輸入法準(zhǔn)備詞庫數(shù)據(jù),量身編制好數(shù)據(jù)庫格式。
所謂巧婦難為無米之炊,做輸入法嘛,其實最核心的部分就是將用戶的輸入映射成相應(yīng)的詞組,沒有數(shù)據(jù),那一切也就無從談起。假設(shè)你要做的一款拼音類型的輸入法,那問題會簡單很多,互聯(lián)網(wǎng)是個大海洋,一般而言,網(wǎng)絡(luò)上都可以找到你需要的數(shù)據(jù),下載到這些數(shù)據(jù)之后,你可能還需要寫一些程序來處理一下,將他們轉(zhuǎn)換成你需要的格式。而如果你要做的是一款新型的形碼方案,問題會棘手一些,你可能需要自己去編碼,建議你找或者是做一個便于你編碼的工具。
編制好合適的數(shù)據(jù)庫格式非常重要。正確、合適的格式要在滿足運行性能的前提下完成各式各樣的詞組檢索操作,同時又不能占用太大的體積。編制一個正確的合適的格式大概有以下幾條原則:
- 數(shù)據(jù)要素齊全;編制數(shù)據(jù)格式的時候,可以預(yù)留一列作為備用列;更改數(shù)據(jù)庫的格式,增加新的內(nèi)容都比較麻煩,尤其是在輸入法發(fā)布之后。
- 數(shù)據(jù)應(yīng)盡可能對齊;這樣便于檢索,不整齊的數(shù)據(jù)格式難于檢索,也會無端地浪費性能和儲存空間;
- 減少無用的冗余信息,在滿足需要的前提下選擇合適的儲存類型;要預(yù)判這個列的信息未來會在哪個范圍內(nèi)波動,比如儲存詞條的類型,是自帶的,還是用戶造的,還是導(dǎo)入的,表示范圍不可能成百上千,那么使用一個字節(jié)就足夠了,沒有必要更多。
掌握Sqlite的使用方法,熟練地使用SQL語言,并了解相關(guān)的優(yōu)化技巧。
有了數(shù)據(jù)之后,我們接下來要選擇數(shù)據(jù)的載體。你可以自己編制一個數(shù)據(jù)文件格式,然后自己編寫一套檢索算法,又或者根據(jù)我的建議,選擇Sqlite數(shù)據(jù)庫,省心省力。
Sqlite是Android和iOS平臺都自帶有的數(shù)據(jù)庫程序,關(guān)于Sqlite優(yōu)點的資料應(yīng)該是俯拾皆是,讀者自己可以找一找,我這里就不贅述了。我建議選擇Sqlite的理由很簡單,就是你不需要再自己去實現(xiàn)一個詞組的檢索算法。要實現(xiàn)一個好的檢索算法是相當(dāng)困難的,這可能會占用你開發(fā)的大部分精力,而你勞神費力,最后可能會沮喪地發(fā)現(xiàn),你做出來的效果還不如Sqlite提供的能力。所以這個選擇非常關(guān)鍵。
而作為一名輸入法開發(fā)者,對Sqlite數(shù)據(jù)庫最大的擔(dān)心莫過于其性能是否可以經(jīng)受得起對用戶流暢使用輸入法這一要求的考驗。根據(jù)我長期的使用體驗,Sqlite的性能是夠用的,特別是在硬件性能已經(jīng)突飛猛進的今天,我甚至基于Sqlite實現(xiàn)了一個整句引擎都木有問題的啦。所以你可以大膽地選用Sqlite作為數(shù)據(jù)庫程序,如果你確實不放心,你也可以選擇設(shè)計一層與數(shù)據(jù)庫實現(xiàn)無關(guān)的接口,在你認(rèn)為Sqlite不能滿足你需求的時候用其他實現(xiàn)替換他。如果數(shù)據(jù)檢索成為了你輸入法的性能瓶頸,那么很大可能是你的數(shù)據(jù)格式編制得不合理,無法發(fā)揮Sqlite的性能特點,也可能是你優(yōu)化得不到位所致。只有在確定Sqlite已無優(yōu)化潛力,而性能仍不達標(biāo)的情況下再去考慮其他實現(xiàn)。但是在最開始,先讓你的輸入法能夠運行起來才是第一要務(wù),所以Sqlite絕對既是不二之選,也是不二之選。熟悉相應(yīng)平臺的圖形繪制機制和事件處理機制
這一點對于任何應(yīng)用來說都是必須的,但對于輸入法來說,這一部分我們可能需要懂得更深入一些。
很少有一個應(yīng)用,會像輸入法一樣,在一個狹小的空間內(nèi)排放下如此之多的控件(就qwerty鍵盤而言,鍵盤上保守估計至少是30個按鍵,這僅僅是看得見的部分)。更多的控件就意味著更多的內(nèi)存。令人苦惱的是,系統(tǒng)似乎并不會因此就對輸入法更寬容,事實恰恰相反,所以我們只能在很有限的內(nèi)存空間內(nèi)做我們想做的事情。有些時候,為了達成目的,我們需要自己去實現(xiàn)一些控件的效果,甚至是完全由自己去繪制整個鍵盤(我就這么干過,但我奉勸各位,盡可能別走這條路)。而有些時候,輸入法在圖形上的開銷太大會影響到使用的流暢度,所以我們也需要在優(yōu)化界面流暢度上挖空心思。
如果你要實現(xiàn)的是一種基于非常規(guī)的復(fù)雜交互的輸入法,比如說滑行輸入的方式,那么我們就很難基于現(xiàn)成的事件監(jiān)聽器去實現(xiàn)這種交互,這個時候,我們就需要自己去截獲這些事件,重新去分派他們或者處理他們。了解不同的字符集,了解如何顯示emoji,了解繁簡體的轉(zhuǎn)換
Android和iOS現(xiàn)在都采用的Unicode字符集,大多數(shù)字符的顯示都不成問題,但比如我們是在window上開發(fā),然后在Android上顯示,這個時候,我們就需要小心字符集不同可能帶來的問題。而如果你要開發(fā)的輸入法是小語種或者會涉及很生僻的生僻字,那么字符集問題都會很令人頭疼。
現(xiàn)在的大多數(shù)輸入法都會帶有emoji的輸入功能,但在編程的時候,emoji字符可不是以我們平時所看到的樣子存在于文本中的,我們會以編碼的形式存儲他們,在需要顯示和輸入時再進行轉(zhuǎn)換。這個開源項目大家可以參考一下emojione。
支持繁體對于部分中文輸入法用戶來說也是必不可少的,我們可以選擇在數(shù)據(jù)庫中存儲繁簡兩種版本的字符,但我覺得更合理的做法是在需要的時候進行轉(zhuǎn)換。OpenCC是繁簡體轉(zhuǎn)換方面做得非常出色的開源項目。了解接入第三方SDK的方法
現(xiàn)在語音輸入已經(jīng)很常見了,比如說你在用TNT的時候,emmmm,很酷哦。所以如果能給你的輸入法接入語音輸入的能力,絕對是一件錦上添花的事情,也可能是雪中送炭的事情(像歲寒輸入法,有的用戶打字一著急,就干脆用語音了,你們開心就好咯)。自己去開發(fā)一個語音輸入引擎,實在是很不現(xiàn)實。市面上有不少大廠提供了語音輸入的接口,我們可以通過接入這些接口來擴展我們輸入法的能力,我所知道的有訊飛、百度和靈云。其中,靈云還提供手寫識別的服務(wù),感興趣的可以了解一下。了解馬爾科夫鏈和統(tǒng)計語言模型的相關(guān)理論,掌握圖的相關(guān)算法
到目前為止,你已經(jīng)可以開發(fā)出一款說得過去也說不過去的機械式檢索輸入法了。說得過去的部分是,這款輸入法已經(jīng)可以用了,如果是像五筆那一類型的形碼輸入法,其實基本上就這樣啦。但說不去的部分是,如果是拼音輸入法,你的輸入法里還缺一個整句引擎。據(jù)我所知,這個部分目前沒有任何公司提供接口可以調(diào)用,所以我們只好自己去實現(xiàn)?;隈R爾科夫鏈的統(tǒng)計語言模型,我們就可以開發(fā)一款整句引擎出來,這里有我一篇之前寫的文章:如何實現(xiàn)自己的一個智能整句引擎,僅供參考。這個整句引擎的本質(zhì)是求解圖的最短路徑(開銷最大部分其實是檢索詞組間的轉(zhuǎn)移概率),所以掌握圖的相關(guān)算法也是必須的,推薦閱讀《算法》。
這里還有sunpinyin輸入法開源項目,大家可以學(xué)習(xí)。
非技術(shù)上的
- 你要有一個始終如一的理念。作為一個輸入法開發(fā)者,我們既是開發(fā)者,也是設(shè)計師,我們要自己把握開發(fā)的尺度,決定什么要做,什么不要做。響應(yīng)用戶的呼聲很重要,但遵從一個始終如一的理念同樣重要;
- 做一個基本的輸入法出來其實不是多困難的事情,但是要做一個好用的輸入法,可能需要付出非常巨大的努力,輸入法的特點在于他幾乎有無窮無盡的細(xì)節(jié)需要雕琢;
- 開發(fā)輸入法很大程度上是一件吃力不討好的事情,如果你是出于學(xué)習(xí)的目的來開發(fā)一款輸入法的,那也不錯,如果不是,那你要做好血本無歸的準(zhǔn)備。就我而言,我做的第一版輸入法,全世界都沒人會用,只有我一個人會用;我做的第二版輸入法,別人也會用了,但是沒有人用;我做的第三版輸入法,終于有人愿意用了。
- 輸入法改變不了世界,沒有什么太特別的魔力。他只不過是一種用戶黏性比較強的輸入工具而已。
言盡于此,以上。