わりと特定条件下で発生する問題。(潜在的には多そうな話?)
特定条件下って
おおまかにこの2条件が成立すると起きる現象だと思ってます。該当しない人には無関係だと思うのでスルーしてください。
- java実行時のファイルエンコーディング設定を明示していない。もしくは、明示しているがUTF-8ではない。
- Android SDKのライセンス文書自体を取り扱う。文書の最終取り扱い先がUTF-8で動く。
AndroidSDK のライセンス
- https://developer.android.com/sdk/terms.html
- https://dl-ssl.google.com/android/repository/repository.xml
よく見ると、Androidリポジトリのxmlに記述されているライセンス文書のうち、
セクション12.1.だけに 全角アポストロフィ が入っている。
全角:12.1 -略- (including reasonable attorneys’ fees)
半角:12.1 -略- (including reasonable attorneys' fees)
(上がもともとあったもの、下が半角にしたもの)
## 起きた実例
kivy-buildozer では、androidアプリのビルド時にAndroidSDKの各パッケージをダウンロードするように動いている。
これは内部的に、
「
$ tools/android update sdk
コマンドを実行して、出力をキャプチャして表示しつつ、[y/n]のダイアログを見つけたらyを投げる」
という処理をしているのだが、java実行時のfile.encodingがUTF-8になっていないと、コマンド側で出力されるテキストがUnicodeで出力されずに、python側がデコード失敗するというものだった。
対処
基本的には「呼び出す側のプログラムと呼び出される側(今回はandroid)での、処理エンコーディングのミスマッチ」が原因っぽいので次のような対処をしていけばいい?
1. java実行時のエンコーディングを明示して実行させる
buildozerでの対応はこれ。
JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8
で指定できるので、あらかじめenvに入れておくか、実行時に指定できるようにしておけばOK
(多分こっちが正答)
2. デコード失敗を無視して処理を進める
対処の方式として一つの手ではあるけど、肝心なところがこの現象に引っかかったりすると良くない。
あと、ライセンス文書を加工するのってまずいような。
3. java のエンコーディングに呼び出し側を合わせる
思いつきで書いたけどたぶん無理。直前にわからないから
4. 呼び出す側をjavaで作る
もともと、javaのプログラム上でandroidコマンドを実行する分にはエンコーディングが揃ったままなので行ける気もする。試してないけど
5. androidコマンドは別に実行する
buildozerのケースでも、失敗後にandroid-GUIでパッケージをインストールさせてしまえば以降はそんなに問題にならないとは言える。
でもそれじゃせっかくのツールが意味が無いかな、と。
所感
書けば書くほど、レアケース感がすごい。(javaのファイルエンコーディングに関する記事はBlogでかなり見るので、あらかじめ指定してそうなのが強い)
が、後で思い出す時に便利そうなのと、Pull Requestを投げるいい機会になったので、とりあえず書いてみた。