Android 6.0.1无法创建目录(Environment.getExternalStoragePublicDirectory(Environment.directory_PICTURES),“MyCameraApp”;?

Android 6.0.1无法创建目录(Environment.getExternalStoragePublicDirectory(Environment.directory_PICTURES),“MyCameraApp”;?,android,android-intent,android-camera,Android,Android Intent,Android Camera,我正在使用WebView和摄像头功能构建我的第一个Android应用程序。我一直在关注官方文件,遇到了很多问题 例如,根据文档,我使用下面提供的示例代码: /** Create a file Uri for saving an image or video */ private static Uri getOutputMediaFileUri(int type){ return Uri.fromFile(getOutputMediaFile(type)); } /** Create

我正在使用WebView和摄像头功能构建我的第一个Android应用程序。我一直在关注官方文件,遇到了很多问题

例如,根据文档,我使用下面提供的示例代码:

/** Create a file Uri for saving an image or video */
private static Uri getOutputMediaFileUri(int type){
      return Uri.fromFile(getOutputMediaFile(type));
}

/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type){
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
              Environment.DIRECTORY_PICTURES), "MyCameraApp");
    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    if (! mediaStorageDir.exists()){
        if (! mediaStorageDir.mkdirs()){
            Log.d("MyCameraApp", "failed to create directory");
            return null;
        }
    }

    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    File mediaFile;
    if (type == MEDIA_TYPE_IMAGE){
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
        "IMG_"+ timeStamp + ".jpg");
    } else if(type == MEDIA_TYPE_VIDEO) {
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
        "VID_"+ timeStamp + ".mp4");
    } else {
        return null;
    }

    return mediaFile;
}
它在我运行安卓5.0.2的设备上运行得非常好,但它无法在安卓6.0.1上创建目录。我正在调试这个过程,我注意到它在代码的这一部分返回
null

if (! mediaStorageDir.mkdirs()){
            Log.d("MyCameraApp", "failed to create directory");
            return null;
        }
我在网上搜索,我发现了关于这个问题的类似线索,比如(,和)等等

在最后一个线程中,如果你读到一条评论,它会说:

如果您正在寻找存储卡路径,则无法在所有设备上找到它。根据官方文件,公共静态字符串目录\图片标准目录,用于放置用户可用的图片。您无法控制返回的路径

这是有道理的,这就是为什么我想使用默认值,但由于它在Android 6.0.1上不起作用,我想通过指定保存文件的位置来应用一种变通方法。摘自官方文件:

MediaStore.EXTRA_输出-此设置需要一个Uri对象,指定保存图片的路径和文件名。此设置是可选的,但强烈建议使用。如果未指定此值,相机应用程序将使用返回的intent的intent.getData()字段中指定的默认名称将请求的图片保存在默认位置

如果我理解正确,我可以指定另一个文件路径位置,例如
mediaFile=file.createTempFile(时间戳、扩展名、mWebViewActivity.getExternalCacheDir())

这个小的变通方法帮助我克服了安卓6.0.1和安卓5.0.2中的问题,但当我检索到的数据为空时,这两种情况都有不利的一面

从文档中检索数据的代码示例:

如果我更改了位置以从
File mediaStorageDir=new文件(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),“MyCameraApp”)保存数据
to
mediaFile=File.createTempFile(时间戳,扩展名,mWebViewActivity.getExternalCacheDir()),这两种环境(5.0.2和6.0.1)都可以克服问题并“假装工作正常”。所谓假装,我的意思是我没有收到任何错误或应用程序没有崩溃,但有一个问题

如文件所述:

如果未指定此值,相机应用程序将使用返回的intent的intent.getData()字段中指定的默认名称将请求的图片保存在默认位置

这就是五月的情况。两个版本都无法理解我正在使用的
Uri
。在5.0.2版本中,它能够获取默认位置并“以某种方式”完成该过程,但在6.0.1版本中,由于它找不到默认位置,它只获取图片/视频,但不将其存储在任何位置,以便检索,并且数据为空

我已在我的清单文件中包括:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

**更新:**添加选择器

public Intent makeChooserIntent(String title, WebChromeClient.FileChooserParams fileChooserParams) {

        Intent galleryIntent = new Intent(Intent.ACTION_CHOOSER, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

        Intent chooser = Intent.createChooser(galleryIntent, title);

        List<Intent> intentActivitiesList = new ArrayList<>();
        if (checkCameraHardware(mWebViewActivity.getApplicationContext())) {
            Log.d(TAG, "Device has camera.");

            //create new Intent
            Intent videoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
            Intent imageIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);

            intentActivitiesList.add(imageIntent);
            intentActivitiesList.add(videoIntent);
            intentActivitiesList.add(fileChooserParams.createIntent());

            try {
                imageFileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
                videoFileUri = getOutputMediaFileUri(MEDIA_TYPE_VIDEO);  // create a file to save the video
            } catch (IOException e) {
                Log.e(TAG, "Error creating tmp file: " + e);
            }

            chooser.putExtra(MediaStore.EXTRA_OUTPUT, videoFileUri); // set the image file name
            chooser.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); // set the video image quality to high
            chooser.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri);
            chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentActivitiesList.toArray(new Parcelable[]{}));
        }
        return chooser;
    }
public Intent makechooserint(字符串标题,WebChromeClient.FileChooserParams FileChooserParams){
Intent gallerycontent=新意图(Intent.ACTION\u选择器、MediaStore.Images.Media.EXTERNAL\u内容\u URI);
Intent chooser=Intent.createChooser(gallerycontent,title);
List intentActivitiesList=新建ArrayList();
如果(选中CameraHardware(mWebViewActivity.getApplicationContext()){
Log.d(标签“设备有摄像头”);
//创造新的意图
意向视频意向=新意向(MediaStore.ACTION\u VIDEO\u CAPTURE);
Intent-imageIntent=newintent(android.provider.MediaStore.ACTION\u-IMAGE\u-CAPTURE);
intentActivitiesList.add(imageIntent);
意向性列表。添加(视频意向);
添加(fileChooserParams.createIntent());
试一试{
imageFileUri=getOutputMediaFileUri(媒体类型图像);//创建一个文件以保存图像
videoFileUri=getOutputMediaFileUri(媒体类型视频);//创建一个文件以保存视频
}捕获(IOE异常){
Log.e(标记“创建tmp文件时出错:”+e);
}
chooser.putExtra(MediaStore.EXTRA_OUTPUT,videoFileUri);//设置图像文件名
chooser.putExtra(MediaStore.EXTRA_VIDEO_QUALITY,1);//将视频图像质量设置为高
putExtra(MediaStore.EXTRA_输出,imageFileUri);
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS,intentActivitiesList.toArray(新地块[]{}));
}
返回选择器;
}
我认为错误来自选择器,因为它没有寻找正确的Uri

所以我的问题是,这是一个错误,还是我设置了一些完全错误的东西

很抱歉问了这么长的问题/帖子,但我试图解释我应用的所有问题/解决方案


如果我在Android 5.0.2上调试检索到的数据,如果我更改了

,如果您的目标是SDK 23并使用棉花糖(只要清单中有正确的权限,棒棒糖就可以正常工作),那么您需要在运行时获得危险的权限:考虑录制音频/读取/写入外部存储(正确的做法)作为“危险权限”。Hello@MarkKeen是的,我注意到,最初我的应用程序崩溃了,但后来我发现了解决方法,正如你从链接中指出的,它实际上非常简单。我修改了build.gradle以使用
targetSdkVersion 22
,它在两个Android版本(5.0.2和6.0.1)上都运行良好。但你说的是真的。你面临的具体问题是什么?如果你
public Intent makeChooserIntent(String title, WebChromeClient.FileChooserParams fileChooserParams) {

        Intent galleryIntent = new Intent(Intent.ACTION_CHOOSER, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

        Intent chooser = Intent.createChooser(galleryIntent, title);

        List<Intent> intentActivitiesList = new ArrayList<>();
        if (checkCameraHardware(mWebViewActivity.getApplicationContext())) {
            Log.d(TAG, "Device has camera.");

            //create new Intent
            Intent videoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
            Intent imageIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);

            intentActivitiesList.add(imageIntent);
            intentActivitiesList.add(videoIntent);
            intentActivitiesList.add(fileChooserParams.createIntent());

            try {
                imageFileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
                videoFileUri = getOutputMediaFileUri(MEDIA_TYPE_VIDEO);  // create a file to save the video
            } catch (IOException e) {
                Log.e(TAG, "Error creating tmp file: " + e);
            }

            chooser.putExtra(MediaStore.EXTRA_OUTPUT, videoFileUri); // set the image file name
            chooser.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); // set the video image quality to high
            chooser.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri);
            chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentActivitiesList.toArray(new Parcelable[]{}));
        }
        return chooser;
    }