本儲存庫保存 ASUS ZenUI Keyboard APK 的反編譯成果,以及使用 Apktool 重新封裝、對齊與簽署 APK 的 GitHub Actions 工作流程。
Warning
這不是原始 Android Studio/Gradle 專案。儲存庫不包含原始 Java/Kotlin、C/C++、Gradle、Android NDK 或原始簽章金鑰;內容由既有 APK 解包與反編譯而來。apktool/ 才是可重建 APK 的來源目錄,jadx/ 僅供閱讀與研究,不能直接參與建置。
Caution
APK 包含 ASUS、Nuance XT9、Vision Objects/MyScript、Google、Facebook 等可能受授權或商標保護的元件與資產。持有、研究、修改、重新封裝、簽署或散布前,應自行確認原始 APK、native library、語言資料庫與其他內容的適用授權、裝置條款及法規。本儲存庫的結構說明不構成授權。
- 專案定位
- 目前 APK 資訊
- 快速建置
- 整體結構
- apktool:可重建 APK 的工作目錄
- jadx:唯讀程式碼參考
- 輸入法架構與執行流程
- 原生函式庫與 ABI
- 資料庫、詞典與手寫資料
- Android 元件與系統整合
- CI 建置與輸出
- 修改指引
- 已知限制與風險
- 驗證清單
- 名詞與路徑對照
此專案的工作模式是「APK 反編譯、檢視、有限修改與重新封裝」,不是一般從原始碼編譯的 Android app。其兩個主要目錄有完全不同的責任:
| 目錄 | 產生工具 | 用途 | 是否用於 APK 建置 |
|---|---|---|---|
apktool/ |
Apktool | APK 的資源、Manifest、Smali、原生庫與原始封裝中保留的檔案 | 是 |
jadx/ |
JADX | Dalvik bytecode 還原後的 Java 參考碼與資源副本 | 否 |
因此,修改行為必須依目標選擇正確位置:
- 修改資源、Manifest、Smali、封裝檔案或 native library:修改
apktool/。 - 追蹤 Java 類別、理解呼叫關係、搜尋 native API:閱讀
jadx/sources/。 - 不要將
jadx/sources/當作可直接編譯的原始碼,也不要預期修改它會出現在輸出 APK。 - 不要手動同步編輯
apktool/與jadx/的資源副本;jadx/是分析快照,不是第二份真實來源。
下列資訊由 apktool/apktool.yml 與 apktool/AndroidManifest.xml 取得:
| 項目 | 值 |
|---|---|
| 套件名稱 | com.asus.ime |
| APK 來源檔名 | ZenUI_keyboard.apk |
| 版本名稱 | 1.7.10.29_190130 |
| 版本代碼 | 1510710145 |
| 最低 Android API | 19 |
| 目標 Android API | 26 |
| Manifest compile SDK 標記 | 23 |
| 主輸入法服務 | com.asus.ime.IME |
| Application 類別 | com.asus.ime.AsusImeApplication |
| 目前封裝 native ABI | 僅 armeabi-v7a |
這些值描述的是反編譯來源 APK 的狀態,並不代表重新封裝後能取得原廠系統權限、原廠簽章信任或 OEM 預載整合。
本機建置至少需要:
- Java 17
- Android SDK Build Tools,包含
zipalign與apksigner - Apktool 2.x
GitHub Actions 已自動安裝 Java、Android SDK 與最新版 Apktool;本機可依相同流程操作。
以下命令假設 apktool、zipalign 和 apksigner 已位於 PATH:
apktool b apktool -o output/ZenUI_keyboard-unsigned.apk
zipalign -v -p 4 output/ZenUI_keyboard-unsigned.apk output/ZenUI_keyboard-aligned.apk
keytool -genkeypair -v \
-keystore output/debug.keystore \
-alias androiddebugkey \
-keyalg RSA \
-keysize 2048 \
-validity 10000 \
-storepass android \
-keypass android \
-dname "CN=Android Debug,O=Android,C=US"
apksigner sign \
--ks output/debug.keystore \
--ks-pass pass:android \
--key-pass pass:android \
--ks-key-alias androiddebugkey \
--out output/ZenUI_keyboard.apk \
output/ZenUI_keyboard-aligned.apk
apksigner verify -v output/ZenUI_keyboard.apkCI 的實際腳本位於 .github/workflows/build-apk.yml。它會把產物上傳為 GitHub Actions artifact,並在 main 分支或 v* tag 時建立/更新 GitHub Release。
- 新簽署的 APK 無法直接覆蓋以 ASUS 原始憑證簽署的
com.asus.ime。 - 若目標裝置已有原廠 ZenUI Keyboard,通常必須先解除安裝原版,或先進行完整的 package/authority/intent 遷移後改用新套件名稱。
- 解除安裝會清除該 package 的 app 資料與使用者詞典;請先備份必要資料。
- 以不同簽章重裝系統預載 IME,可能失去系統整合、privileged 權限或 OEM 專用功能。
ZenUI_keyboard/
├── .github/
│ └── workflows/
│ └── build-apk.yml # CI:解包目錄重建、zipalign、簽署、發布
├── apktool/ # 唯一可由 Apktool 重建 APK 的目錄
│ ├── AndroidManifest.xml # App 元件、權限、Intent、套件識別
│ ├── apktool.yml # Apktool 解包/重建描述與 APK 版本資訊
│ ├── assets/ # 設定、XT9 語言資料庫與手寫資料
│ ├── lib/ # 封裝的原生 .so,現有僅 armeabi-v7a
│ ├── original/ # 原 APK 的簽章/封裝中繼資料保留區
│ ├── res/ # Android 資源:layout、drawable、values、xml 等
│ ├── smali/ # classes.dex 還原後的可建置 Dalvik bytecode
│ └── unknown/ # Apktool 無法歸類而按原樣保留的檔案
├── jadx/ # 僅用於閱讀與逆向分析的輸出
│ ├── resources/ # JADX 擷取的 Manifest、res、assets、lib 副本
│ └── sources/ # 還原的 Java 參考碼
└── README.md # 本文件
apktool/ 與 jadx/ 都可能出現同一資產或 native library,例如:
apktool/lib/armeabi-v7a/libjni_xt9input.so
jadx/resources/lib/armeabi-v7a/libjni_xt9input.so
這不表示專案有兩個獨立的 XT9 實作,而是兩個反編譯工具各自輸出的副本。重建流程只會使用前者。
Manifest 定義 Android 元件、權限、深層連結、服務以及 OEM 整合。最重要項目如下:
| 類型 | 名稱/設定 | 用途與注意事項 |
|---|---|---|
| Application | com.asus.ime.AsusImeApplication |
全域初始化;宣告 directBootAware=true |
| IME Service | com.asus.ime.IME |
透過 android.permission.BIND_INPUT_METHOD 註冊為輸入法 |
| Clipboard Provider | com.asus.ime.clipboard.provider.DatabaseProvider |
私有剪貼簿資料 provider |
| 設定 Activity | com.asus.ime.settings.* |
一般、外觀、智慧輸入、中文輸入等設定畫面 |
| 首次啟動 Activity | com.asus.ime.firstlaunch.* |
安裝後導覽、選擇語言與背景檢查 |
| Nuance Connect Service | com.nuance.connect.service.ConnectClient |
語言/內容服務,運行於 :ACService 行程 |
| Dialer API Receiver | com.asus.ime.dialerapi.ApiReceiver |
接收手寫初始化、辨識、釋放與支援清單廣播 |
| Theme Store 元件 | com.asus.ime.theme.*、com.asus.ime.store.* |
佈景、商店、背景編輯;多數使用獨立 com.asus.ime.store.process 行程 |
| 外部資料傳輸 | DataTransferReceiver、DataTransferService |
ASUS/FutureDial 資料傳輸整合 |
Manifest 同時宣告數個選用 shared library:
<uses-library android:name="com.visionobjects.im" android:required="false"/>
<uses-library android:name="com.visionobjects.myscript.engine" android:required="false"/>
<uses-library android:name="com.visionobjects.myscript.hwr" android:required="false"/>
<uses-library android:name="com.visionobjects.myscript.inksearch" android:required="false"/>它們屬於 Vision Objects/MyScript 手寫功能的系統或 OEM 相依項。required=false 僅代表 package manager 不會因此拒絕安裝;程式實際使用相關功能時仍可能因庫不存在、ABI 不相容或系統 linker 限制而失敗。
Manifest 包含網路、儲存、震動、設定與系統整合權限,例如:
INTERNET
ACCESS_NETWORK_STATE
READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE
VIBRATE
WRITE_SETTINGS
WRITE_SECURE_SETTINGS
STATUS_BAR
INTERACT_ACROSS_USERS
其中 WRITE_SECURE_SETTINGS、STATUS_BAR、INTERACT_ACROSS_USERS 等通常是 signature、privileged 或受限權限。重新簽章後的一般側載 APK 即使在 Manifest 中保留宣告,也通常無法獲得授權;修改功能時必須將「未獲授權」視為正常環境,並提供安全降級。
此檔是 Apktool 的解包描述,不是 Gradle 設定。它保存:
- 原始 APK 檔名與 Apktool 版本。
minSdkVersion、targetSdkVersion、versionCode與versionName。- 重建資源時所需的 framework ID。
- 不壓縮檔案清單,例如
resources.arsc、圖片與音效格式。 - 需要按原樣保留的
unknown/檔案壓縮方式。
變更版本或重建行為前,應理解 Apktool 的格式與限制;不要將它誤認為 app 的 build configuration。
此目錄包含 Android 編譯資源。資源限定詞保留了原 APK 的螢幕尺寸、方向、密度、語系和 API 版本適配,例如:
| 路徑模式 | 目的 |
|---|---|
layout/、layout-land/ |
一般與橫向介面 layout |
layout-sw600dp/、layout-sw720dp/ |
平板或較大螢幕 layout |
drawable-* |
密度、方向、尺寸與 API 等級對應的圖片/shape 資源 |
mipmap-* |
App icon 等 launcher 資源 |
values/ |
預設字串、色彩、樣式、尺寸、陣列與設定值 |
values-zh-rTW/、values-zh-rCN/、values-zh-rHK/ |
中文地區化資源 |
其他 values-<locale>/ |
多國語系翻譯 |
xml/ |
IME method metadata、keyboard layout、偏好與其他 XML 設定 |
raw/ |
原始音訊或不適合轉成一般資源的檔案 |
menu/、anim/、color/ |
功能選單、動畫與顏色狀態資源 |
資源修改注意事項:
- 保留資源名稱與引用關係,否則 Smali 中的
R資源 ID 引用可能失效。 - 不應隨意刪除同一資源的密度、螢幕寬度或 API 版本變體。
- 反編譯的
res/可重建但不一定和原始開發專案的資源結構完全一致;大型重構前先保留完整備份並驗證 APK。
Smali 是 DEX bytecode 的文字表示,重建 APK 時由 Apktool 編譯回 DEX。這是本專案中唯一能實際修改 app 邏輯的位置。
主要命名空間包含:
| 路徑 | 內容 |
|---|---|
smali/com/asus/ime/ |
輸入法 UI、控制器、XT9 wrapper、設定、佈景、剪貼簿、資料傳輸與手寫入口 |
smali/com/nuance/ |
XT9、Connect/SwypeConnect 及相關服務邏輯 |
smali/com/visionobjects/ |
MyScript/Vision Objects 手寫包裝層 |
smali/jp/co/omronsoft/openwnn/ |
OpenWnn 相關資料結構與日文輔助邏輯 |
smali/android/support/、smali/androidx/ 或第三方命名空間 |
隨 APK 打包的支援函式庫與第三方程式 |
smali/com/asus/ime/ 的重要類別:
| 類別 | 職責 |
|---|---|
IME.smali |
Android InputMethodService 主入口,管理輸入生命週期與視圖 |
InputMethods.smali |
管理語言、輸入模式、目前 engine 與功能能力 |
InputView.smali、InputViewSwitcher.smali |
輸入面板建立及不同視圖切換 |
KeyboardViewEx.smali、KeyboardEx.smali |
鍵盤繪製、按鍵、觸控與版面資料 |
AlphaInput.smali、ChineseInput.smali、KoreanInput.smali |
各語系輸入引擎的 Java/Smali facade |
NativeAlphaInput.smali、NativeChineseInput.smali、NativeConfigInput.smali |
對 libjni_xt9input.so 的 JNI 宣告 |
japanese/ |
日文轉換、羅馬字與日文 XT9 wrapper |
hw/ |
T9 Write 與 Vision Objects/MyScript 手寫流程 |
CandidatesListView.smali、WordListViewContainer.smali |
候選字 UI 與選字處理 |
EmojiInputView.smali、EmojiContainerView.smali |
Emoji 輸入介面 |
clipboard/ |
剪貼簿資料與 provider |
settings/ |
設定 Activity 與偏好處理 |
theme/、store/ |
主題、背景與商店功能 |
connect/ |
語言、詞典或內容下載整合 |
dialerapi/ |
撥號器/外部手寫 API |
修改 Smali 時應注意:
.locals、.registers、invoke 指令參數與型別必須正確。- Java 反編譯碼可用來理解意圖,但不能保證與 Smali 一一對應。
- native 方法簽名、類別名稱與 package 名稱是 JNI 合約的一部分;任意重新命名會讓 native library 無法註冊或找不到方法。
- 對
AndroidManifest.xml、res/或 package 名稱的修改,往往也需要同步處理 Smali 內的硬編碼字串、authority、intent action 和資源引用。
assets/ 不經 Android 資源 ID 編譯,程式以 AssetManager 或檔案路徑讀取。
apktool/assets/
├── conf/ # XT9/MyScript 執行期設定
└── databases/ # XT9 詞典、鍵盤、手寫與使用者資料設定
詳見後面的資料庫、詞典與手寫資料。
APK 內的 native library 依 ABI 分類。目前唯一目錄為:
apktool/lib/armeabi-v7a/
├── libjni_xt9input.so
├── libminizip.so
└── libCV-crypto.so
詳見原生函式庫與 ABI。
此目錄保留原 APK 的封裝中繼資料,通常包含原始 META-INF 簽章檔案與原始 manifest 等內容。它的用途是保留解包資訊與協助重建,不代表輸出 APK 仍能維持原始簽章。
重新封裝後必須使用自己的合法 keystore 簽署;不要嘗試將原始 META-INF 簽章檔直接沿用到已修改的 APK。
這裡存放 Apktool 無法分類、但必須以原始路徑與壓縮方式保留的檔案,例如 AIDL 或 GWT XML。除非已確認其消費端與封裝規則,否則應避免刪除或改名。
JADX 將 DEX 還原成較接近 Java 的形式,適合搜尋與理解邏輯:
jadx/
├── resources/
│ ├── AndroidManifest.xml # Manifest 參考副本
│ ├── assets/ # assets 參考副本
│ ├── lib/ # native library 參考副本
│ └── res/ # 資源參考副本
└── sources/
├── com/asus/ime/ # ZenUI Keyboard 主要邏輯
├── com/nuance/ # XT9/Connect 邏輯
├── com/visionobjects/ # MyScript/Vision Objects wrapper
├── jp/co/omronsoft/openwnn/ # OpenWnn 相關程式
└── 其他第三方套件
| 目的 | 建議先閱讀的檔案 |
|---|---|
| IME 啟動與 Android 生命週期 | jadx/sources/com/asus/ime/IME.java |
| Native engine 載入 | jadx/sources/com/asus/ime/Input.java |
| XT9 build info 與語言列舉 | jadx/sources/com/asus/ime/NativeConfigInput.java |
| 拉丁輸入流程 | AlphaInput.java、AlphaInputView.java、NativeAlphaInput.java |
| 中文輸入流程 | ChineseInput.java、ChineseInputView.java、NativeChineseInput.java |
| 日文輸入流程 | japanese/JapaneseInput.java、japanese/NativeJapaneseInput.java |
| T9 手寫 | hw/t9/ 與 NativeWriteAlpha.java、NativeWriteChinese.java |
| Vision Objects 手寫 | hw/vo/ 與 com/visionobjects/im/ |
| 語言/詞典設定 | DatabaseConfig.java、Utils.java、connect/ |
| 鍵盤資料轉換與 native callback | Input.java、XT9KeyboardDatabase.java |
| 設定、語言切換與 UI | InputMethods.java、Settings.java、settings/ |
- 類別、變數與泛型名稱可能不完整或由工具推測。
- 控制流程、匿名類別、例外處理、switch 與型別轉換可能與原始碼不同。
- 某些程式可能無法完整反編譯,或附帶 JADX 警告。
- Java 參考碼絕不能取代實際
apktool/smali/的驗證。
遇到不一致時,以 Smali、DEX 行為與實機測試為準。
Android Input Method Framework
|
v
com.asus.ime.IME (InputMethodService)
|
v
InputMethods / InputViewSwitcher
|
+--> AlphaInput / AlphaInputView -----------+
+--> ChineseInput / ChineseInputView --------+--> Native*Input JNI facade
+--> JapaneseInput / JapaneseInputView ------+ |
+--> T9 Write handwriting -------------------+ v
libjni_xt9input.so (ARMv7 only)
|
+--> XT9 LDB/HDB/HWR assets
+--> UDB/ASDB/DLM runtime data
+--> Vision Objects handwriting
|
v
com.visionobjects.im wrapper
|
v
OEM/system MyScript libraries and handwriting resources
Vision Objects/MyScript 手寫是獨立 native 相依鏈,並不完全由 libjni_xt9input.so 提供。
Input 類別固定載入 jni_xt9input:
System.loadLibrary("jni_xt9input");對應封裝檔為:
apktool/lib/armeabi-v7a/libjni_xt9input.so
Input.java 的 static initializer 會捕捉並忽略載入例外。這不是 fallback:若 library 載入失敗,後續第一次呼叫 native API 時仍可能以 UnsatisfiedLinkError、初始化錯誤或功能崩潰表現。修改時應避免繼續吞掉可診斷錯誤。
NativeConfigInput 在 InputMethods 建立期間查詢 build info、核心版本與可用語言,因此 XT9 library 缺失不只影響輸入候選,也可能使輸入法啟動期失敗。
| Facade | Native 功能 |
|---|---|
NativeConfigInput |
XT9 build info、核心版本、可用語言 |
NativeAlphaInput |
拉丁輸入、候選、校正、手勢、UDB、ASDB、DLM |
NativeChineseInput |
拼音、注音、倉頡、筆畫、中文候選與詞典 |
japanese/NativeJapaneseInput |
日文轉換、候選、羅馬字、範圍轉換 |
hw/t9/NativeWriteAlpha |
拉丁 T9 手寫 |
hw/t9/NativeWriteChinese |
中文 T9 手寫 |
com.nuance.xt9.input.* |
舊式 Nuance/XT9 API 與部分中文/辨識流程 |
這些 JNI API 的規模很大。替換一個 native library、換用不同世代 XT9 blob 或改寫其中一個 facade,都不能只以 library 能被 System.loadLibrary 載入為驗收標準。
| 檔案 | 載入/用途 | 目前 ABI 狀態 |
|---|---|---|
libjni_xt9input.so |
XT9 主輸入 engine;拉丁、中文、日文、T9 Write、設定查詢 | 僅 armeabi-v7a |
libminizip.so |
Content Vendor 壓縮檔處理 | 僅 armeabi-v7a |
libCV-crypto.so |
Content Vendor 加解密;Java 同時嘗試載入 crypto 與 CV-crypto |
僅 armeabi-v7a |
libjni_xt9input.so 是 32 位元 ARM ELF。現有專案中沒有:
arm64-v8a/native library。- XT9 的 C/C++ 原始碼。
- Nuance XT9 SDK header、靜態庫或可重編譯資產。
Android.mk、Application.mk、CMakeLists.txt、Gradle NDK 設定。
Android 64 位元程序不能載入 32 位元 ARM ELF。因此下列作法無效:
將 armeabi-v7a/libjni_xt9input.so 複製到 arm64-v8a/
只改檔名或壓縮 APK
重新簽署 APK
修改 ABI 資料夾名稱
若 APK 只帶 armeabi-v7a,它僅能在系統仍提供 32 位元 app runtime 時以 32 位元程序執行。部分 arm64 裝置仍支援這種相容模式;64-bit-only 裝置則無法執行,且不能透過 Manifest 或 target SDK 修復。
完整功能的最低前提是取得具合法使用與再散布權的、相容版本的完整 arm64 元件組,而非單一檔案:
arm64-v8a/libjni_xt9input.so
arm64-v8a/libminizip.so
arm64-v8a/libCV-crypto.so
任何實際使用的其他 JNI library
相容的 XT9 語言/手寫資料庫
相容的 MyScript/Vision Objects arm64 相依或可接受的功能降級
候選 arm64 library 應至少驗證:
- 檔案為
ELF64與AArch64,不是將 ARMv7 blob 改名。 - 所有
DT_NEEDED相依庫可在目標 Android 版本與 linker namespace 中載入。 - 現有 Java/Smali JNI 合約可完整註冊及呼叫。
- 現有 LDB/HDB/HWR、使用者詞典與設定格式相容,或有明確遷移方式。
- Alpha、Chinese、Japanese、T9 Write 與設定語言列舉均可實機測試。
- 沒有相容元件的手寫功能必須在 UI 和外部 API 層明確停用,不能等到使用時崩潰。
apktool/assets/
├── conf/
│ ├── Engine.properties # MyScript/Vision Objects engine 路徑設定
│ ├── LanguageManager.properties # 手寫語言管理設定
│ ├── Recognizer.properties # 手寫辨識設定
│ └── <locale>.lang # 多語系設定資料
└── databases/
├── config/
│ └── databases.conf # 語言 ID、LDB、手寫、UDB、ASDB 等映射
├── ldb/ # XT9 language database
├── hldb/ # 中文手寫相關 XT9 資料
├── hwr/ # 手寫模板與辨識資料
├── kdb/ # 鍵盤資料庫/版面相關資料(如存在)
└── mdb/ # OEM 補充詞庫資料(如存在)
實際可用的子目錄與檔名由原 APK 決定;重建前不應自行假設所有資料都能由替代引擎讀取。
apktool/assets/databases/config/databases.conf 是 XT9 資料映射的核心設定。主要 section 包含:
| Section | 用途 |
|---|---|
[kdb] |
鍵盤資料庫映射與 layout/language ID 關係 |
[ldb] |
語言 ID 至 XT9 language database 的映射 |
[hwr_dic] |
手寫字典;缺少時可由 XT9 LDB 在執行期轉換 |
[hwr_db_template] |
手寫辨識模板資料 |
[mdb] |
OEM 補充詞庫 |
[udb] |
執行期產生的使用者詞典 |
[asdb] |
自動替換資料庫 |
[cdb] |
中文附加字典資料 |
例如繁體與簡體中文 LDB 包含:
ZHtbUNps_Big5_bpmf_pinyin_CJ_xt9.ldb
ZHsbUNps_GB18030_xt9_big.ldb
副檔名相同不等於格式相容。不同 XT9 世代、OEM 客製版本或替代引擎可能無法載入既有 .ldb、.hldb、.hdb、.bin、UDB、ASDB 或 DLM 資料。
程式會把 APK assets 的資料複製到 app 私有工作目錄,並以該目錄作為資料庫與使用者資料的實際位置。部分設定同時保留原廠 /system/usr/xt9/databases/ldb/ 路徑假設。
這表示側載環境必須測試:
- assets 是否確實被複製到 app 私有目錄。
- 無法讀取
/system/usr/xt9/時是否能使用 app 內建資料。 - 升級、重新簽章、改 package 或清除資料後,UDB/ASDB/DLM 的行為是否符合預期。
- 資料庫載入失敗時是否會安全降級,而非讓 IME 在啟動時崩潰。
apktool/assets/conf/Engine.properties 明確記錄 Android ARMv7 平台名稱,並設定:
com.visionobjects.myscript.engine.library=/system/lib/libMyScriptEngine.so這是原廠系統映像相依的證據。現代裝置可能改用不同分區、64 位元庫目錄、linker namespace 或完全不提供該 library。不要把此設定視為可跨裝置保證運作的公開 SDK 配置。
輸入法服務由以下 Manifest 項目註冊:
<service
android:name="com.asus.ime.IME"
android:permission="android.permission.BIND_INPUT_METHOD">
<intent-filter>
<action android:name="android.view.InputMethod"/>
</intent-filter>
<meta-data android:name="android.view.im" android:resource="@xml/method"/>
</service>修改 IME 名稱、service 類別、輸入 subtype 或 package 時,應同步檢查:
res/xml/method.xml或其對應 IME metadata。InputMethodManager設定與選取流程。- 設定 Activity、首次啟動流程與 Launcher entry。
- 任何指向
com.asus.ime的硬編碼 intent、provider authority、shared preference、檔案路徑與 broadcast action。
Manifest 宣告多種對外或跨程序介面:
| 介面 | 例子 | 風險 |
|---|---|---|
| Broadcast receiver | 手寫、輸入裝置、佈景、資料傳輸 action | exported 狀態與輸入驗證要重新檢視 |
| Content provider | 剪貼簿、佈景偏好、Facebook provider | 改 package 時 authority 必須唯一且同步更新 |
| Bound service | IME、RemoteService、RemoteSettingService | AIDL descriptor、permission 與外部客戶端相容性 |
| Deep link | asusime://settings、佈景頁面 |
package/host 路由與 exported 安全性 |
| 獨立 process | :ACService、com.asus.ime.store.process |
資料可見性、初始化順序、native library 載入與 crash 隔離 |
特別是 ApiReceiver 的手寫廣播入口,即使一般鍵盤 UI 未顯示手寫功能,外部呼叫仍可能觸發 native library 載入。因此功能降級時必須同時處理 UI 和 API 入口。
若無法移除原廠 com.asus.ime,通常需要改用新的 package/application ID。這是高風險改動,至少涉及:
- Manifest 根節點 package、每個 component 與相對類別名稱。
- provider authority,例如
com.asus.ime.provider.clipboard與com.asus.ime.store.preference。 - Java/Smali 中的 package、class name、反射字串與 intent action。
- AIDL、Binder descriptor、外部 API、深層連結與分享 URI。
- app 私有資料目錄、資料庫遷移、使用者詞典及偏好設定。
- JNI class/method 名稱或
RegisterNatives對應關係。
不要將 package rename 視為單純替換字串;必須在獨立分支中進行,並逐項做安裝、啟動、IME 啟用、provider、手寫和資料遷移測試。
工作流程檔: .github/workflows/build-apk.yml
| 事件 | 條件 |
|---|---|
| Push | main 分支或 v* tag |
| Pull request | 目標為 main |
| 手動執行 | GitHub Actions workflow_dispatch |
Checkout
-> 安裝 Temurin JDK 17
-> 安裝 Android SDK
-> 下載最新版 Apktool
-> apktool b apktool
-> zipalign
-> 產生 CI 用 debug keystore
-> apksigner sign
-> apksigner verify
-> 上傳 artifact
-> main / tag 時發布 GitHub Release
| 檔案 | 用途 |
|---|---|
output/ZenUI_keyboard-unsigned.apk |
Apktool 原始重建結果,不能安裝 |
output/ZenUI_keyboard-aligned.apk |
已 zipalign,尚未簽署 |
output/ZenUI_keyboard-signed.apk |
已簽署的中間產物 |
output/ZenUI_keyboard.apk |
CI 上傳 artifact 與 Release 發布檔 |
目前工作流程每次執行都建立新的 debug keystore。這代表每次 CI build 的簽章可能不同,因此:
- 新版無法直接覆蓋舊版,除非使用相同 keystore。
- 無法作為正式發布或長期更新機制。
- 安裝測試版前可能需要先解除安裝舊測試版。
若需要可更新的測試或正式版本,應以安全的 GitHub Actions secret 管理固定且合法的 signing key,並設計金鑰備份、輪替、版本與發布政策。不得把私人或正式 keystore 直接提交到儲存庫。
適用範圍:圖示、layout、字串、顏色、樣式、XML 設定。
- 在
apktool/res/找到目標資源與所有相關限定詞版本。 - 保留資源名稱和 XML 結構,避免破壞既有
RID 引用。 - 執行
apktool b apktool。 - 安裝到測試裝置,至少檢查直向、橫向、不同密度與語系。
適用範圍:輸入模式、設定、UI 邏輯、功能開關與錯誤處理。
- 在
jadx/sources/搜尋對應 Java 類別、呼叫端與資源引用。 - 在
apktool/smali/找到相同類別的實際可建置版本。 - 僅做最小變更,確認 register 數量、型別與控制流程。
- 建置、簽署、安裝後,驗證 cold start、啟用 IME、實際輸入與設定切換。
- 對所有 native 相關路徑,觀察
logcat中的UnsatisfiedLinkError、dlopen failed、SIGSEGV、SIGABRT與 tombstone。
適用範圍:LDB、HDB、HLDB、MDB 與 databases.conf。
- 先記錄原檔雜湊、大小、語言 ID 與來源版本。
- 確認目標 engine 支援該資料庫格式;檔案副檔名相同不足以證明相容。
- 修改
[ldb]、[hwr_dic]、[hwr_db_template]等映射時,檢查 app 私有工作目錄與系統路徑 fallback。 - 測試所有受影響語言的載入、輸入、候選、使用者詞典與 process restart。
適用範圍:XT9、手寫、Content Vendor、壓縮或加密功能。
- 先列出
System.loadLibrary、System.load、native 方法及其所有呼叫端。 - 在 UI、初始化流程、Broadcast API、Service 和背景任務都加入一致的 capability gate。
- 不要只在單一畫面隱藏按鈕;外部 receiver 或啟動期
NativeConfigInput仍可能載入 library。 - 必須有明確 fallback、停用狀態或使用者可理解的錯誤訊息。
- 以不含該庫的測試 APK 驗證所有錯誤路徑不會崩潰。
- 將
armeabi-v7a的.so改放到arm64-v8a/。 - 以反編譯 Java 宣告推導或重建 Nuance XT9 native engine。
- 未驗證下刪除
unknown/、original/或系統整合 manifest 元件。 - 未取得相容性與授權確認就替換為其他 OEM 的同名 XT9 blob。
- 未盤點 provider、AIDL、JNI、hard-coded package string 前直接全域取代
com.asus.ime。 - 將 CI 自動產生的 debug signing key 視為可穩定更新的發行簽章。
反編譯結果可供研究與有限調整,但會遺失原始專案結構、註解、型別資訊、建置腳本、原始 native source、依賴版本與簽章供應鏈資訊。任何較大規模功能開發都應評估重新建立一個合法、可維護的 Android 原始碼專案。
目前沒有 arm64-v8a library。64-bit-only 裝置不能使用現有 native 功能,這是二進位 ABI 問題,不是資源、Manifest 或重新簽章問題。
程式、設定與 manifest 顯示它原本是 ASUS 預載環境的一部分,可能依賴:
- 原廠簽章與 privileged/signature permission。
/system/usr/xt9/資料庫。/system/lib/libMyScriptEngine.so與 Vision Objects shared library。- ASUS 系統 app、服務、property、佈景與資料傳輸協定。
因此「能重建 APK」不代表「在所有現代 Android 裝置上所有功能都可用」。
不同簽章的 APK 無法升級已安裝的原廠同 package app。改 package 號會避開衝突,但需要完整遷移 component、provider、資料與 JNI 相依。
來源 APK 的 targetSdkVersion=26。現代 Android 對 exported 元件、儲存空間、背景執行、隱私、網路安全、安裝來源與 IME 行為有更嚴格的要求;若目標是正式長期維護,不能只停留在重打包。
輸入法可接觸極敏感的使用者輸入。對網路、下載、分析、第三方 SDK、剪貼簿、外部 API、使用者詞典和 crash log 的任何修改,都應以最小權限、資料最小化、離線優先與清楚告知為原則。
每次修改後至少確認下列項目。
-
apktool b apktool成功,沒有資源或 Smali 編譯錯誤。 -
zipalign -c -v 4 <apk>驗證成功。 -
apksigner verify -v <apk>驗證成功。 - APK 可安裝於測試裝置,並已處理原廠 package/簽章衝突。
- 冷啟動、強制停止後啟動、重新開機後啟動均正常。
- 可在系統設定中啟用輸入法。
- 可切換為目前輸入法並顯示鍵盤。
- 英文/拉丁按鍵、Shift、Caps Lock、退格、Enter、數字、符號與 Emoji 正常。
- 直向、橫向、窄螢幕與平板 layout 不重疊或崩潰。
- 設定畫面、首次啟動流程與語言切換正常。
-
System.loadLibrary("jni_xt9input")在目標 ABI 成功,或功能被安全停用。 - Alpha 引擎可建立、開始、輸入、取得候選、完成與釋放。
- 中文模式可載入對應 LDB,並測試拼音/注音/倉頡/筆畫中產品聲稱支援的模式。
- 日文模式可進行羅馬字、假名與候選轉換。
- 使用者詞典、ASDB、DLM 在 app 重啟後行為符合預期。
- 無
/system/usr/xt9/或資料庫檔遺失時不崩潰。
- T9 Write 拉丁與中文手寫正常,或功能明確停用。
- Vision Objects/MyScript 手寫正常,或 UI/API 均安全降級。
-
ApiReceiver的初始化、辨識、支援清單、釋放 action 不會在 native library 缺失時崩潰。 - 未授予 privileged permission 時,相關功能不會使 app 無法啟動。
- 檢查
logcat,沒有UnsatisfiedLinkError、dlopen failed、SIGSEGV、SIGABRT或 native tombstone。 - 檢查 exported receiver/provider/service,確認不會接受未驗證的敏感輸入。
- 在無網路情境下測試,確保下載/分析服務不阻擋本地輸入。
- 在密碼與敏感欄位中確認候選、學習、剪貼簿與網路行為符合隱私政策。
| 名詞 | 本專案中的位置或含義 |
|---|---|
| APK 重建來源 | apktool/ |
| Java 研究參考碼 | jadx/sources/ |
| 實際可修改邏輯 | apktool/smali/ |
| Android Manifest | apktool/AndroidManifest.xml |
| APK 解包描述 | apktool/apktool.yml |
| Android 資源 | apktool/res/ |
| 非資源原始檔 | apktool/assets/ |
| XT9 主 JNI library | apktool/lib/armeabi-v7a/libjni_xt9input.so |
| XT9 語言資料庫 | apktool/assets/databases/ldb/ |
| XT9 資料映射 | apktool/assets/databases/config/databases.conf |
| MyScript engine 路徑設定 | apktool/assets/conf/Engine.properties |
| CI 工作流程 | .github/workflows/build-apk.yml |
| 主要 IME service | com.asus.ime.IME |
| JNI 載入入口 | jadx/sources/com/asus/ime/Input.java |
| XT9 能力查詢 | jadx/sources/com/asus/ime/NativeConfigInput.java |
- 將
apktool/視為唯一可發布產物的編輯來源。 - 將
jadx/視為閱讀、搜尋與驗證假設的輔助資料。 - 每次變更保持小範圍,建立、簽署並在實機驗證後再繼續。
- 不要隱藏 native library、系統庫或權限失敗;要有可觀察的 log 與可預期的降級行為。
- 對 package rename、ABI 遷移、詞典格式替換、原生 blob 更新或手寫引擎替換,先做獨立可行性驗證,再進入完整實作。
- 對 IME 的輸入資料、詞典、剪貼簿、網路與遙測功能採取最高標準的隱私與安全審視。