最近在做遠程控制功能,手機APP端控制電腦桌面端。有個功能是APP端輸入文本,顯示在電腦端輸入框內。由于當前遠程控制功能還在初級階段,只需實現輸入數字、英文大小寫字母、特殊符號和部分控制鍵,故只需要彈出一個安全鍵盤。
安全鍵盤在很多銀行APP里使用廣泛,一般用來輸入密碼。密碼通常是由數字、英文大小寫字母和特殊符號構成,沒有中文,所以輸入法鍵盤也就不需要支持語言切換,純英文鍵盤就可以。
一般來說,安全鍵盤可自定義,繼承KeyboardView
然后設置自定義的布局文件(需要在xml目錄下自定義)。
但是在深入反編譯研究了TeamViewer的APK后發現,TeamViewer彈出的安全鍵盤并不是自定義的而是系統自帶的。有以下證據:
- 資源文件里沒有安全鍵盤相關的icon和字符串;
- 這個所謂的“安全鍵盤”的彈出動畫明顯區別于自定義的鍵盤,因為他的布局文件里在自定義的鍵盤上方加了一個工具條,在“安全鍵盤”彈出時可以看到工具條明顯的跳動,而自定義的鍵盤彈出時并沒有;
- 彈出這個“安全鍵盤”時,無法截屏,彈出自定義鍵盤時可以截屏。當然禁止截屏可以在代碼里通過
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE)
實現,但是在全局搜索了反編譯之后的代碼并沒有發現,可見無法截屏應該是因為這個“安全鍵盤”導致的。
安全鍵盤(因為無法截圖,只能拍照了)
TeamViewer彈出的這個“安全鍵盤”完全滿足我們的需求,而且不用自定義,省去了很多繁瑣的工作。既然這樣,那么我們也嘗試彈出這個“安全鍵盤”吧。
不好意思,這個小功能點我斷斷續續做了兩天,還是無果。彈出來的輸入法永遠都是系統默認的搜狗。是我太菜了么?
當時我甚至在懷疑,這個“安全鍵盤”的xml布局文件是不是運行時動態地從服務器上下載的,導致我無法在反編譯的資源文件里找到一些線索。但轉念一想,這也不是什么機密文件,而且這個鍵盤布局也不需要更新變化(不像銀行的安全鍵盤,按鍵位置隨機變化)。然后我又仔仔細細的搜索了setKeyboard
這個自定義鍵盤必須使用的方法,想著是不是有遺漏之處,依然毫無線索。
再結合前面說到的三條這個“安全鍵盤”是系統自帶的而不是自定義的證據,我再次確定,這個“安全鍵盤”確實是系統自帶的,一定是還有什么鍵盤屬性設置,被我遺漏了。
于是我又開始仔細看著枯燥的反編譯后的代碼文件。功夫不負有心人,在TeamViewer接收文字輸入的控件里(繼承了AutoCompleteTextView
),他們重寫了onCreateInputConnection
方法,里面有兩句配置:
paramEditorInfo.inputType = 524433;
paramEditorInfo.imeOptions = 268435457;
看到的第一眼,直覺告訴我,就是你們了。先不管這兩個數字看起來有多么奇怪,立馬先給自己的app加上再說,運行起來,打開一看,搞定!
興奮了幾分鐘,冷靜下來,準備繼續深入分析下去。
刪掉了paramEditorInfo.imeOptions = 268435457;
這句后,依然可以彈出安全鍵盤。那么這個524433
到底是何方神圣呢?
524433
的16進制是0x80091
,EditorInfo
的inputType
可以設置的類型在android.text.InputType
這個類里,并沒有0x80091
這個值,那么應該是多個value位運算后的結果。在InputType
里湊了一會,發現是以下幾個:
TYPE_CLASS_TEXT(0x00000001)
,TYPE_TEXT_VARIATION_VISIBLE_PASSWORD(0x00000090)
和TYPE_TEXT_FLAG_NO_SUGGESTIONS(0x00080000)
和。
完整的代碼是:
editorInfo.inputType = InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
TYPE_CLASS_TEXT
一般和TYPE_TEXT_FLAG_NO_SUGGESTIONS
一起使用來禁止輸入法鍵盤的智能提示功能(這個功能對暫時只支持輸入單個字符的遠程控制來說,確實不需要)。TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
這個用來讓密碼可見。嘗試了下設置inputType
為單獨的TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
并不能彈出安全鍵盤,當然其他兩個更不行了。必須將inputType
設置成InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
才能有效彈出安全鍵盤。
以上測試結果基于OPPO Reno。
后面又測試了Pixel,結果大跌眼鏡。Pixel根本彈不出所謂的安全鍵盤,不過也跟安全鍵盤無異。只是這個鍵盤就是默認的輸入法鍵盤,隨便寫一個EditText
設置屬性android:inputType="none"
就可以調出來。只是彈出這個鍵盤后,依舊可以截屏(因為就是一個普通的鍵盤)。
猜測是OPPO對輸入法做了魔改,禁用了系統自帶的默認鍵盤,改為了搜狗鍵盤。
假如說一開始就用Pixel做嘗試,就不會遇到彈不出“安全鍵盤”的問題,也就不會耽擱那么多時間來想方設法尋求解決方案。不過也正因如此,才發現了這么一些有趣的現象和解決方案。