調用Android系統自帶相機拍照,從相冊中獲取圖片(兼容7.0系統)

一,前言:
在日常的手機應用開發過程中,經常會遇到上傳圖片的需求,像上傳頭像之類的,這就需要調用系統的相機,相冊獲取照片。但是在Android 系統7.0之后認為這種操作是不安全的,這篇文章主要就是記錄7.0獲取照片遇到的問題。

二,FileProvider介紹
都說google官方文檔是最好的學習資料,我也帶著英語字典上來瞅了瞅。
https://developer.android.google.cn/reference/android/support/v4/content/FileProvider
1,借用google官方的原話:
FileProvider is a special subclass of ContentProvider that facilitates secure sharing of files associated with an app by creating a content:// Uri for a file instead of a file:/// Uri.
大致意思是說:FileProviders 是ContentProvider的子類,它通過創建content://Uri 來取代file:///Uri,從而有助于安全地共享與應用程序相關聯的文件。。。。詳細信息還是到google官網看吧

三,拍照
1,權限申請
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2,調用系統相機
public void camera() {
if (hasSdcard()) {
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
tempFile = new File(Environment.getExternalStorageDirectory(),
PHOTO_FILE_NAME);
Uri uri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
uri = FileProvider.getUriForFile(
this, "com.camera.fileprovider",
tempFile);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
} else {
uri = Uri.fromFile(tempFile);
}
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(intent, PHOTO_REQUEST_CAMERA);
}
}
private boolean hasSdcard() {
return Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED);
}
1>調用相機之前我們可以創建一個臨時文件tempFile指定拍照后原照片的位置
2>在7.0系統之后通過FileProvider.getUriForFile(Context context,String authority,File file);獲取content://Uri代替file:///Uri。第二個參數authority和下文將要說到的android:authorities="com.camera.fileprovider" 一致
為Uri臨時授權:
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
3>讓系統將原照片存放在指定的位置
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);

3,在AndroidManifest.xml清單文件中注冊FileProvider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.camera.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
1>name:使用v4中默認的FileProvider
2>authorities:和上一步中獲取content://Uri保持一致。格式:xxx.fileprovider,xxx可以自定義
3>grantUriPermissions:是否允許為content://Uri賦予臨時權限
4>meta-data:配置的是我們允許訪問的文件的路徑,需要使用XML文件進行配置。name是固定寫法,resource是指定的配置的xml文件

4,在res目錄下創建一個名為xml的文件夾,然后在該文件夾下創建名為provider_paths的xml文件
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external_storage_root"
path="." />
<external-path
name="external_storage_root_file"
path="./Demo/" />
</paths>

具體的路徑和命名規則如下:
命名 對應目錄
<files-path name = "name" path = "path"/> Context.getFilesDir()
<cache-path name = "name" path = "path"/> Contest.getCacheDir()
<external-path name = "name" path = "path"/> Environment.getExternalStorageDirectory()
<external-files-path name = "name" path = "path"/> Context.getExternalFilesDir()
<external-cache-path name = "name" path = "path"/> Context.getExternalCacheDir()
<external-media-path name = "name" path = "path"/> Context.getExternalMediaDirs()
如果需要使用FileProvider獲取某個目錄下文件的uri,按照上表的對應關系在XML文件中聲明就可以了

5,接收相機返回的code值
if (requestCode == PHOTO_REQUEST_CAMERA && resultCode == RESULT_OK) {
Uri uri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
uri = FileProvider.getUriForFile(
this, "com.camera.fileprovider",
tempFile);
} else{
uri = Uri.fromFile(tempFile);
}
crop(uri);
}
1>根據臨時文件拿到Uri

6,裁剪圖片
mCropImageFile = new File(Environment.getExternalStorageDirectory(), //創建一個保存裁剪后照片的file
"crop_image.jpg");
// 裁剪圖片意圖
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
intent.putExtra("crop", "true");
// 裁剪框的比例,1:1
intent.putExtra("aspectX", 1); //X方向上的比列
intent.putExtra("aspectY", 1); // Y方向上的比例
intent.putExtra("outputX", 250); //裁剪區的寬度
intent.putExtra("outputY", 250); //裁剪區的高度
intent.putExtra("outputFormat", "JPEG");// 圖片格式
intent.putExtra("noFaceDetection", true);// 取消人臉識別
intent.putExtra("return-data", false); //是否在Intent中返回數據
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mCropImageFile));
startActivityForResult(intent, PHOTO_REQUEST_CUT);

7,獲取裁剪后的圖片
if (requestCode == PHOTO_REQUEST_CUT) {
Bitmap headerBitmap = BitmapFactory.decodeFile(mCropImageFile.getAbsolutePath());
File file;
if (headerBitmap != null)
try {
file = BitmapToFile.saveFile(headerBitmap, "crop.png");
} catch (IOException e) {
e.printStackTrace();
}
try {
if (tempFile != null)
tempFile.delete();
if (mCropImageFile != null) {
mCropImageFile.delete();
}
} catch (Exception e) {
e.printStackTrace();
}
}

四,相冊獲取照片
1,調用系統相冊
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, PHOTO_REQUEST_GALLERY);
2,接收系統相冊返回的數據
if (requestCode == PHOTO_REQUEST_GALLERY) {
// 從相冊返回的數據
if (data != null) {
// 得到圖片的全路徑
Uri uri = data.getData();
crop(uri);
}
}
1>返回的數據是Intent對像,getData()返回的就是相冊中照片存放的Uri
3,裁剪和上面的邏輯是一樣的,都是根據傳入的Uri

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容