2013-08-02 36 views
2

我一直在这一整天,似乎无法得到它的工作。根据之前从事这项工作的人员,它以前的工作方式。如何让相机意图将照片放入内部存储?

cameraIntent = new Intent("android.media.action.IMAGE_CAPTURE"); 
     String imageName = CustomApp.getTimeStamp(0) ; 
     String path = CustomApp.getCurrentActivity().getDir("images", Context.MODE_WORLD_WRITEABLE).getPath()+File.separator+imageName; 

     File file = new File(path) ; 
     Uri img = Uri.fromFile(file) ; 

     Intent passthruDataIntent = new Intent(); 

     cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, img); 
     CustomApp.getCurrentActivity().startActivityForResult(cameraIntent, CustomConstants.REQUESTCODE_CAMERA); 

类似的代码已经张贴在这里,但它似乎并没有在4.2.2上我的Nexus 4的工作。我尝试了外部存储,然后工作正常。任何有关为什么它可能无法正常工作的见解将非常有帮助。谢谢。

回答

7

内部存储对于每个应用程序都是私人的 - 第三方相机应用程序无权写入您的内部存储。

+0

看,这正是我一直在向我的老板争论的。但不幸的是,因为上面的代码在某些时候起作用,他们希望以这种方式保留它。我确实有一个问题需要澄清:'Context.MODE_WORLD_WRITEABLE'。我做了一个假设,它允许任何应用程序从那里访问文件和内容,因为它不是'MODE_PRIVATE'。这种方式不行吗?基本上,因为它在某个时刻起作用,我会猜测它做了什么。 – Andy

+1

@Andy:“但不幸的是,因为上面的代码在某种程度上起作用,他们希望以这种方式保留它” - 如果有的话,它肯定无法可靠地工作。 “这种方式不行吗?” - 是和不是。是的,该文件是可写的。您认为相机应用正在写入现有文件。它可能会尝试删除现有文件并创建一个新文件。 *目录*是世界可写的,它们可能会成功删除,但是您将无法读取结果文件,因为它将由其他应用程序拥有,可能是私有的。 – CommonsWare

+2

@Andy:请记住,有数千个相机应用程序,其中任何一个都可以响应你的'Intent',因此行为会有所不同。仅仅因为你可以获得一个应用程序的工作并不意味着所有人都会。 – CommonsWare

1

我有同样的问题。我通过首先将照片保存在外部存储器上然后复制到内部存储器来解决这个问题。希望这可以帮助。

+0

对于SD卡不可用的情况,请参阅http://stackoverflow.com/questions/7720383/camera-intent-not-saving-photo –

4

我在为同样的问题而战,并在很久后得到了一个问题的解决方案,但我相信这可能对社区有用。

随着在Android 6.0/API级别23中引入新的dynamic permissions,主题问题变得尤为重要,因为您需要在运行时请求权限并处理用户的接受和拒绝反应。要使用相机活动,您需要首先请求相应的许可(android.permission.CAMERA)。然后,如果您将图片存储在外部目录中,用户还需要将相应的权限android.permission.READ_EXTERNAL_STORAGE授予您的应用。在用户即将执行预期动作时(例如,如果在按下“拍照”按钮之后出现照相机访问许可请求),运行时许可请求对于用户来说似乎是自然的。但是,如果您使用外部存储器保存照相机图像,则当您的应用程序拍摄照片时,您需要同时询问两个权限:(1)使用照相机和(2)访问外部存储器。后者可能令人沮丧,因为它不一定清楚为什么你的应用程序尝试访问用户文件,而用户只需要拍摄照片。

解决方案允许避免外部存储并直接保存相机图片包括使用content providers。按照storage options documentation

Android提供了一个方法可以让你即使您的私人数据暴露给其他应用程序 - 与内容提供商。内容提供者是一个可选组件,它公开对您的应用程序数据的读/写访问权限,受到您想强加的任何限制。

这正是你所需要的,以允许对相机的活动直接保存图片到你的应用程序的本地存储,让您可以轻松地访问它,然后没有要求额外的权限(只需要相机访问被授予)。

提供了一个带有代码示例的好文章here。以下通用代码受本文启发,在我们的应用程序中用于实现。

内容提供商类:

/** 
* A content provider that allows to store the camera image internally without requesting the 
* permission to access the external storage to take shots. 
*/ 
public class CameraPictureProvider extends ContentProvider { 
    private static final String FILENAME = "picture.jpg"; 

    private static final Uri CONTENT_URI = Uri.parse("content://xyz.example.app/cameraPicture"); 

    @Override 
    public boolean onCreate() { 
     try { 
      File picture = new File(getContext().getFilesDir(), FILENAME); 
      if (!picture.exists()) 
       if (picture.createNewFile()) { 
        getContext().getContentResolver().notifyChange(CONTENT_URI, null); 
        return true; 
       } 
     } catch (IOException | NullPointerException e) { 
      e.printStackTrace(); 
     } 
     return false; 
    } 

    @Nullable 
    @Override 
    public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException { 
     try { 
      File picture = new File(getContext().getFilesDir(), FILENAME); 
      if (!picture.exists()) 
       picture.createNewFile(); 
      return ParcelFileDescriptor.open(picture, ParcelFileDescriptor.MODE_READ_WRITE); 
     } catch (IOException | NullPointerException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    @Nullable 
    @Override 
    public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 
     return null; 
    } 

    @Nullable 
    @Override 
    public String getType(@NonNull Uri uri) { 
     String lc = uri.getPath().toLowerCase(); 
     if (lc.endsWith(".jpg") || lc.endsWith(".jpeg")) 
      return "image/jpeg"; 
     return null; 
    } 

    @Nullable 
    @Override 
    public Uri insert(@NonNull Uri uri, ContentValues values) { 
     return null; 
    } 

    @Override 
    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) { 
     return 0; 
    } 

    @Override 
    public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) { 
     return 0; 
    } 
} 

需要内容提供商的应用程序清单中声明:

<provider android:authorities="xyz.example.app" 
     android:enabled="true" 
     android:exported="true" 
     android:name="xyz.example.app.CameraPictureProvider" /> 

最后,使用内容提供商,以捕捉摄像机图像,从调用活动调用以下代码:

Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
// Ensure that there's a camera activity to handle the intent 
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, CameraPictureProvider.CONTENT_URI); 
startActivityForResult(takePictureIntent, 0); 

请不要e相机许可请求需要单独处理(不在所提供的代码示例中完成)。

还值得注意的是,只有在使用构建工具版本23或更高版本时才需要处理权限请求。相同的代码与低级构建工具兼容,并且在您不受运行时权限请求困扰的情况下很有用,但只希望避免使用外部存储。

+0

嗨,我完全知道你没有在这篇文章中处理权限。但是,你能提到一些关于这方面的事情吗?例如 - 我得到“权限拒绝:getCurrentUser()...需要android.permission.INTERACT_ACROSS_USERS” - 无法在清单中添加。所以我仍然相信它必须要求相机应用程序写入我的应用程序的内部存储器......有什么想法? – marienke

+0

这是一个更好的解决方案。 – YellowJ

相关问题