Android assets的一個bug

大頭發表於2013-12-13

由於要顯示一些奇奇怪怪的日文字元,我們在應用裡放了一個字型檔檔案,譬如叫做jp.ttf,放在assets目錄下打包。

開發、除錯一切正常。可是突然發現,在Android 2.2的裝置上,文字無法顯示。折騰一番後發現了一些故事,也產生了更多疑問。

  1. 放在assets目錄下的資原始檔不會被對映到R.java,訪問需要AssetManager類。不同於res/rawres/raw中的資原始檔會被對映到R.java,訪問時使用資源ID。

  2. 能搜尋到很多網頁(但內容幾乎相同)指出AssetManager有個bug,不能處理單個超過1MB的檔案。但沒有說明Android版本。從我們對這個字型檔的使用來看,Android 2.3以上沒有問題。

  3. 找到Android Issue 39041提到AssetManager的一個問題,回覆中5樓bite...@gmail.com說,

    There is a bug in apk de/compression that does not allow using compressed assets which unpack into files larger than 1 mb. This problem is fixed in Android 2.3.

    不知道他是不是Project Member,在7樓,他又說,

    Android smaller than 2.3 DOES NOT GUARANTEE that loading will succeed. This happens more frequently when there are a lot of similar bytes in a row in the asset file, but not necessary. To be sure you have to split the resource file into small files, that's it.

    而Project Member kr...@android.com說,

    Also, do not read files a single byte at a time. Use a large byte buffer.

    不知道這裡“a large byte buffer”要求達到多少。我們的字型檔檔案jp.ttf是超過1MB了,確實也只在Android 2.2上遇到問題。而我們的應用又必須支援Android 2.2。

  4. 又折騰一番後我們發現,把這個jp.ttf改名為jp.xmf,在Android 2.2上就可以正常訪問了。

  5. 無論檔案字尾名是啥,訪問方法是一樣的,

     InputStream in = getResources().getAssets().open("jp.xmf");
    

    第3點裡提到的“a large byte buffer”建議得到了驗證,應用裡由於某種原因需要把這個檔案讀到一個buffer裡再寫到另一個路徑,這個buffer是1KB,如果調整成1MB,jp.ttf就也可以正常訪問了。最初,是這樣訪問的,

    tf = Typeface.createFromAsset(getAssets(), "jp.xmf");
    

    還是不清楚為什麼jp.xmf可以工作,jp.ttf不行?

更新,12月23日。知道了為什麼jp.xmf可以工作,jp.ttf不行。這個問題可能是試圖訪問在打包apk時被壓縮的資原始檔而產生的,因此解決方法確實是改檔案字尾名,改成不會在打包apk時被壓縮的字尾名。譬如mp3、jpg,或者我們曾經嘗試過的xmf。感謝這個提問CommonsWare的回答。

同時,我們也發現之前“5”中的結論是錯誤的,對於jp.ttf,在Android 2.2上增大buffer沒有解決問題。可能當時驗證的小夥伴一時糊塗用錯了手機。關於1MB的問題,還可以參考這個提問

相關文章