Android携帯電話内蔵SDカードパスの取得
, , , 。 , , , ! ~~
, 。 。
1.発生した問題と現象
1)問題が発生した試作品:ZTE U 930 HD(内蔵メモリカード2 G、外付けSDカード挿入なし)他の試作品に問題はない.2)現象:撮影後の写真は関連するロゴを保存できない:
01-19 15:20:25.625: W/System.err(21600): java.io.FileNotFoundException: /mnt/sdcard/MMCamera/photo/20160119152025.jpg: open failed: EACCES (Permission denied)
01-19 15:20:25.625: W/System.err(21600): at libcore.io.IoBridge.open(IoBridge.java:406)
01-19 15:20:25.625: W/System.err(21600): at java.io.FileOutputStream.<init>(FileOutputStream.java:88)
01-19 15:20:25.625: W/System.err(21600): at java.io.FileOutputStream.<init>(FileOutputStream.java:73)
01-19 15:20:25.625: W/System.err(21600): at com.wuxianxi.mmcamera.utils.FileUtil.saveImageToSDCard(FileUtil.java:26)
01-19 15:20:25.625: W/System.err(21600): at com.wuxianxi.mmcamera.view.MainActivity$2.onPictureTaken(MainActivity.java:310)
01-19 15:20:25.625: W/System.err(21600): at android.hardware.Camera$EventHandler.handleMessage(Camera.java:754)
01-19 15:20:25.625: W/System.err(21600): at android.os.Handler.dispatchMessage(Handler.java:99)
01-19 15:20:25.625: W/System.err(21600): at android.os.Looper.loop(Looper.java:137)
01-19 15:20:25.625: W/System.err(21600): at android.app.ActivityThread.main(ActivityThread.java:4424)
01-19 15:20:25.625: W/System.err(21600): at java.lang.reflect.Method.invokeNative(Native Method)
01-19 15:20:25.625: W/System.err(21600): at java.lang.reflect.Method.invoke(Method.java:511)
01-19 15:20:25.625: W/System.err(21600): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
01-19 15:20:25.625: W/System.err(21600): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
01-19 15:20:25.625: W/System.err(21600): at dalvik.system.NativeStart.main(Native Method)
01-19 15:20:25.625: W/System.err(21600): Caused by: libcore.io.ErrnoException: open failed: EACCES (Permission denied)
01-19 15:20:25.625: W/System.err(21600): at libcore.io.Posix.open(Native Method)
01-19 15:20:25.625: W/System.err(21600): at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110)
01-19 15:20:25.625: W/System.err(21600): at libcore.io.IoBridge.open(IoBridge.java:390)
01-19 15:20:25.635: W/System.err(21600): ... 13 more
2.解析原因1)携帯電話でEclipseに接続し、DDMS->File Explorerを確認すると、内蔵ストレージのマウントディレクトリは:/mnt/sdcard 2であるが、私のアプリケーションでストレージパスを取得するコードEnvironmentである.getExternalStorageDirectory()は、「/mnt/sdcard」がストレージパスを取得するエラーを返し、Environmentをさらに確認します.getExternalStorageState(),「removed」に戻ります.Environment.getExternalStorageDirectory()で取得したのは外付けメモリカードですが、外付けSDカードが挿入されていないので記憶できません.2)では、なぜ他のサンプルに問題がないのでしょうか.異なるサンプルでgetExternalStorageDirectory()を呼び出します戻り値は異なります.Androidのドキュメントを調べたところ、元の方法は現在のデバイスメーカーが考えている「外部ストレージ」を返し、外付けのSDカードディレクトリ(Micro SDカード)を返したり、内蔵のSDカードディレクトリ(eMMC)を返したりする可能性があるため、理由が分かった.ほとんどの試作機は、eMMCストレージをEnvironmentにマウントする.getExternalStorageDirectory()このノードは、本物の外付けSDカードを/mnt/external_にマウントします.sd、/mnt/sdcard 2などのノード.しかし、現在の中興ZTE U 930 HDのように、eMMCストレージを/mnt/external_にマウントする部分もある.sd、/mnt/sdcard 2などのノードは、外付けのSDカードをEnvironmentにマウントする.getExternalStorageDirectory()というノード.
3.解決策は前述のようにEnvironmentを使えばgetExternalStorageDirectory()で取得したのは外付けSDカードパスですが、外付けSDカードを挿入していません.このとき、一部のプログラムで使われているデータを内蔵のeMMCストレージで格納するには、どのようにしてこのeMMCストレージのパスを取得すればいいのでしょうか.ネット上でいくつかの資料を探して、比較的に良いのは、システムファイルをスキャンすることです"system/etc/vold.fstab」を実現します.システム/etc/vold.fstabは、Androidのマウントポイント情報を記述する簡単なプロファイルにすぎません.まず、プロファイルを巡回して、すべてのマウントポイントを取得します.
// android
private static List<String> getDevMountList() {
List<String> mVold = new ArrayList<String>(10);
mVold.add("/mnt/sdcard");
try {
File voldFile = new File("/system/etc/vold.fstab");
if(voldFile.exists()){
Scanner scanner = new Scanner(voldFile);
while (scanner.hasNext()) {
String line = scanner.nextLine();
if (line.startsWith("dev_mount")) {
String[] lineElements = line.split(" ");
String element = lineElements[2];
Log.d(TAG, "Vold: element = "+element);
if (element.contains(":"))
element = element.substring(0, element.indexOf(":"));
if (!element.equals("/mnt/sdcard"))
mVold.add(element);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return mVold;
}
そして、Environment.getExternalStorageState()の値は、Environmentを返します.MEDIA_MOUNTED(「mounted」)は、SDカードを内蔵したパスを取得し、正しく記憶できることを示しています.そうでなければ、外付けSDカードを返すと、上のすべてのマウントポイントから格納可能なパスを探して、格納操作を行います.参照コード:
public static String getExternalSdCardPath() {
String path = null;
String state = Environment.getExternalStorageState();
//Environment.getExternalStorageDirectory() SDcard
if (Environment.MEDIA_MOUNTED.equals(state)) {
path = Environment.getExternalStorageDirectory().getPath();
} else { //Environment.getExternalStorageDirectory() SDcard, sdcard
List<String> devMountList = getDevMountList();
for (String devMount : devMountList) {
File file = new File(devMount);
if (file.isDirectory() && file.canWrite()) {
path = file.getAbsolutePath();
break;
}
}
}
Log.d(TAG, "getExternalSdCardPath: path = "+path);
return path;
}
これで、この問題は解決し、プロジェクトもほぼ完成した.ここまで書きましょう.