巷ではマルチユーザーの対応が入ったために4.2から変更されたと言われています。手元では4.3,4.4の端末があるのでこれで現象を確認しました。
androidのプログラム作成時において、多くの場合はリソースとして本体と同じ場所の resや assetsの中に配置するでしょう。ただ頻繁に更新されるファイル”群”や、更新頻度の低い巨大なファイルの場合、毎回APK作成されるのもちょっと無駄です。
このように考えて自分では、ファイルの差し替えがPCから楽にできるように外部SDカードのほうに各種リソースを配置していました(開発時に限る、配布時はこれではマズイと思います)。
このとき、配置してほしい場所がわかるようにパスを表示していたのですがこれが 4.3以降妙なパスになっていることに気付きました。
そのパスがこんな感じです。
”/storage/emulated/0/com.example.testandroid/”
外部SDのマウントポイント+パッケージ名を自分ルールのパスとしていたのですが、今回から emulated とか /0 とか妙な物がみえています。
そして律儀にこのパスにファイルを書き込もうとPCから操作してみたのですが、なんと書き込みができません!
DDMSで上記のファイルパスが出来るようにディレクトリ作成しようとしてNGでした。
この結果、ファイルの書き込みが出来なくなった!とちょっと大騒ぎでした。
しかもこの emulated/0 がリードオンリーでマウントされているのでホントに任意ファイルがおけなくなったか、と思いました。
4.4.2の端末での結果
Environment.getExternalStorageDirectory() 関数では、/storage/emulated/0 が取得できました。getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) などとすると、/storage/emulated/0/Movies が取得できました。
先ほどの話にもありましたが、このフォルダパスは DDMS では辿ることができません。
adb shell でシェルに入ってそのパスを覗こうとしても同様にパスが存在しないと言われてしまいます。
取得できるパスについて
TechBoosterさんの記事”マルチユーザ対応 Android 4.2以降の内部ストレージと外部ストレージ (4.4対応を追記)”によるとこう書かれています。
「ExternalStorageで統一されており内部・外部の区別はありません(区別なく扱えるように内部/外部を判定するメソッドがあります)。過去、フラッシュメモリ容量が少ない時代はExternalStorage(拡張ストレージ)としてSDカードが活用されていましたが内蔵メモリが増えるに従ってSDカードが不要となり、現在のようなアプリケーション領域・内部ストレージ・外部ストレージの3つが入り組んだ構成に至っています。」
結局 getExternalStorageDirectory も内部ストレージの絶対パスを取得するという状態のようです。
関数の名前とこちらが期待する実際の動きは違っていて、内部ストレージに関するものとなっています。
GalaxyS4 4.4.2 の場合
結局一番有効であると言われている vold.fstab の記述からパスを抜いてくればいいのか?と考えて、シェルでそのファイルの中身を見てみましたがこれでもダメなようです。
下記に示す1行のみしかマウントポイントがありませんでしたし、/storage/sdcard1というパスがそもそも存在していないようで cd で移動すらできません。
”dev_mount sdcard /storage/sdcard1 auto /devices/platform/msm_sdcc.3/mmc_host”
実デバイスのフォルダを丁寧に調べてみると、本物の外部SDカードは /storage/extSdCard にマウントされていて、これがPCから接続したときにも “Card” で表示される中身となっているようです。さすがにこのパスを決めうちで使うのも気が引けます・・・。