android调用系统相机拍照

港控/mmm° 2022-07-16 01:57 391阅读 0赞

转载地址:https://my.oschina.net/u/2438532/blog/743160

获取缩略图

直接调取相机拍照,无需任何权限,但是只能获取到缩略图

  1. Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  2. if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
  3. //判断是否有相机应用
  4. startActivityForResult(takePictureIntent, REQ_THUMB);
  5. }
  6. @Override
  7. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  8. super.onActivityResult(requestCode, resultCode, data);
  9. switch (requestCode) {
  10. case REQ_THUMB://返回结果
  11. if (resultCode != Activity.RESULT_OK) return;
  12. Bundle extras = data.getExtras();
  13. Bitmap imageBitmap = (Bitmap) extras.get("data");
  14. mImageView.setImageBitmap(imageBitmap);
  15. break;
  16. }
  17. }

113239_H3a9_2438532.png图片很模糊。一般不采取此种方式

保存全尺寸照片

调取相机拍照保存一个全尺寸的照片,必须提供完整的文件名,相机应用自动保存照片。此时也无需任何权限,创建一个空的临时文件用来保存图片,使用日期时间戳新照片返回一个唯一的文件名

  1. String mCurrentPhotoPath;
  2. private File createImageFile() throws IOException {
  3. // Create an image file name
  4. String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(new Date());
  5. String imageFileName = "JPEG_" + timeStamp + "_";
  6. //.getExternalFilesDir()方法可以获取到 SDCard/Android/data/你的应用的包名/files/ 目录,一般放一些长时间保存的数据
  7. File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
  8. //创建临时文件,文件前缀不能少于三个字符,后缀如果为空默认未".tmp"
  9. File image = File.createTempFile(
  10. imageFileName, /* 前缀 */
  11. ".jpg", /* 后缀 */
  12. storageDir /* 文件夹 */
  13. );
  14. mCurrentPhotoPath = "file:" + image.getAbsolutePath();
  15. return image;
  16. }

每执行一次就会创建一个空的文件

120740_DuL2_2438532.png

利用上述方法创建的文件只能是自己的app访问,随着app的卸载,文件也会删除。对于Android N以下,文件直接Uri.fromFile(file)就可以直接使用,Audroid N 即编译app的版本 compileSdkVersion 24时,此时会报出FileUriExposedException异常,解释如下:

  • 对于面向 Android N 的应用,Android 框架执行的 StrictMode,API 禁止向您的应用外公开 file://URI。
    如果一项包含文件 URI 的 Intent 离开您的应用,应用失败,并出现 FileUriExposedException异常。
  • 若要在应用间共享文件,您应发送一项 content://URI,并授予 URI 临时访问权限。
    进行此授权的最简单方式是使用 FileProvider类。 如需有关权限和共享文件的更多信息,
    请参阅共享文件。

    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    1. // Ensure that there's a camera activity to handle the intent
    2. if (takePictureIntent.resolveActivity(getPackageManager()) != null) {

    //判断是否有相机应用

    1. // Create the File where the photo should go
    2. File photoFile = null;
    3. try {
    4. photoFile = createImageFile();//创建临时图片文件
    5. } catch (IOException ex) {
    6. ex.printStackTrace();
    7. }
    8. // Continue only if the File was successfully created
    9. if (photoFile != null) {
    10. //FileProvider 是一个特殊的 ContentProvider 的子类,
    11. //它使用 content:// Uri 代替了 file:/// Uri. ,更便利而且安全的为另一个app分享文件
    12. Uri photoURI = FileProvider.getUriForFile(this,
    13. "com.example.android.fileprovider",
    14. photoFile);
    15. takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
    16. startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
    17. }
    18. }

现在,需要配置FileProvider。在应用程序的清单,提供者添加到您的应用程序,authorities=”applicationId.fileprovider”,使用时

  1. Uri photoURI = FileProvider.getUriForFile(context,"applicationId.fileprovider", photoFile)

清单中authorities 和 参数authority保持一致。

  1. <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.youga.capturingphotos.fileprovider" android:exported="false" android:grantUriPermissions="true">
  2. <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/>
  3. </provider>
  4. <?xml version="1.0" encoding="utf-8"?>
  5. <paths xmlns:android="http://schemas.android.com/apk/res/android">
  6. <external-path name="my_images" path="Android/data/com.youga.capturingphotos.name/files/Pictures" />
  7. </paths>
  8. @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case REQUEST_TAKE_PHOTO://返回结果 if (resultCode != Activity.RESULT_OK) return; mImageView.setImageBitmap(BitmapFactory.decodeFile(mCurrentPhotoPath)); break; } }

关于FileProvider

FileProvider 是 ContentProvider 的一个特殊的子类,它有利于安全地分享应用相关的文件,通过对一个文件创建content:// Uri而不是file:/// Uri

由于FileProvider的默认功能包括文件的content URI的生成,你并不需要在代码中定义一个子类。相反,你可以在你的应用中包含一个FileProvider通过在XML文件中指定它。对于指定FileProvider,添加一个<provider>元素在你应用的清单文件中。设置android:name属性为android.support.v4.content.FileProvider。根据你控制的域名设置android:authorities属性为一个URI authority(authorities可以随意填写,但是要保证使用时与authority保持一致,推荐applicationId.fileprovider,以免定义重复)。设置android:exported属性为false;FileProvider不需要公开。设置android:grantUriPermissions属性为true,为了允许你进行临时访问文件的授权。

  1. <provider
  2. android:name="android.support.v4.content.FileProvider"
  3. android:authorities="com.youga.fileprovider"
  4. android:exported="false"
  5. android:grantUriPermissions="true">
  6. <meta-data
  7. android:name="android.support.FILE_PROVIDER_PATHS"
  8. android:resource="@xml/file_paths"/>
  9. </provider>

一个FileProvider只能生成一个content URI 对应你事先指定目录下的文件。对于指定一个目录,使用<paths>元素的子元素,在XML中指定它的存储区域和路径。例如,下面的paths元素告诉FileProvider你打算请求你的私有文件区域的 images/ 子目录的content URIs

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <paths xmlns:android="http://schemas.android.com/apk/res/android">
  3. <external-path name="my_images" path="Android/data/com.youga.capturingphotos/files/Pictures/" />
  4. <external-path name="images" path="Pictures/" />
  5. </paths>

file-path 表示你应用内部存储区域的文件的子目录。这个子目录和getFilesDir()的返回值一样。external-path 表示你应用外部存储区域的文件的子目录。这个子目录和getExternalFilesDir()的返回值一样。cache-path 表示你应用内部存储区域的缓存子目录。这个子目录的根目录和getCacheDir()的返回值一样。(如果你修改了provider和paths中的值,需要把应用卸载重装或者开关机一下才能看到变化。)

照片添加到图库

上述保存全尺寸图片时,创建图片临时文件在目录getExternalFilesDir()中,图库无法访问到,我们可以直接创建文件在Environment.getExternalStorageDirectory()目录下;然后发送一个广播让图库更新就好了。当然也可以直接创建文件在图库目录下(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)),即DCIM。此时需要SD卡读写权限。

  1. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  2. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  3. File path = Environment.getExternalStoragePublicDirectory(
  4. Environment.DIRECTORY_DCIM);
  5. // Create an image file name
  6. Log.i(TAG, "path:" + path.getAbsolutePath());
  7. String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(new Date());
  8. String imageFileName = "JPEG_" + timeStamp;
  9. File image = File.createTempFile(
  10. imageFileName, /* 前缀 */
  11. ".jpg", /* 后缀 */
  12. path /* 文件夹 */
  13. );
  14. mPublicPhotoPath = image.getAbsolutePath();

同时发送广播

  1. Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
  2. File f = new File(mPublicPhotoPath);
  3. Uri contentUri = Uri.fromFile(f);
  4. mediaScanIntent.setData(contentUri);
  5. sendBroadcast(mediaScanIntent);

161151_RTRQ_2438532.png

源码放在github上,https://github.com/YougaKing/CapturingPhotos

发表评论

表情:
评论列表 (有 0 条评论,391人围观)

还没有评论,来说两句吧...

相关阅读