HarmonyOS - 本地相冊(cè)的糾葛
??想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):??
??51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)??
前言
二月再見,三月你好,陽(yáng)春三月萬(wàn)物復(fù)蘇,愿一切美好都如約而至。攜手共創(chuàng),鴻蒙社區(qū)。前幾天有個(gè)同事問(wèn)我如何把圖片存在系統(tǒng)相冊(cè)的圖片,當(dāng)時(shí)我就懵逼了,鴻蒙的好像真的不怎么懂?而且這個(gè)操作在我們平時(shí)開發(fā)時(shí)也經(jīng)常用到,所以搞起。
效果展示
踩坑之路
應(yīng)該官網(wǎng)有介紹吧,去官網(wǎng)看看,發(fā)現(xiàn)是有一丟丟介紹
附上鏈接:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/media-data-mgmt-storage-0000001050994909
都說(shuō)安卓和鴻蒙差不多,應(yīng)該思路是差不多的吧,于是找到一片文章(https://harmonyos.51cto.com/posts/10568)里面有MediaStore類,用于操作系統(tǒng)媒體數(shù)據(jù)庫(kù)的類,鴻蒙確實(shí)也有個(gè)類似的類AVStorage,但是現(xiàn)在開放的功能不如MediaStore強(qiáng)大。
后面發(fā)現(xiàn)是鴻蒙的設(shè)計(jì)思路有點(diǎn)像ios的,每個(gè)應(yīng)用的都有獨(dú)自沙河目錄,每個(gè)app的數(shù)據(jù)都存儲(chǔ)在當(dāng)前的應(yīng)用當(dāng)中,這樣大大的確保數(shù)據(jù)的隱蔽性和安全性,這樣比安卓安全性好很多。
保存圖片到系統(tǒng)相冊(cè)
demo布局:
//展示圖片
<Image
ohos:id="$+id:show_photo"
ohos:height="200fp"
ohos:width="200fp"
ohos:image_src="$media:empty"
ohos:scale_mode="zoom_center"
ohos:top_margin="30fp"
/>
//選擇圖片
<Text
ohos:id="$+id:select_photo"
ohos:height="match_content"
ohos:width="match_content"
ohos:background_element="$graphic:background_ability_main"
ohos:layout_alignment="horizontal_center"
ohos:text="選擇圖片"
ohos:text_size="20vp"
ohos:top_margin="10fp"
/>
//保存圖片
<Text
ohos:top_margin="10fp"
ohos:id="$+id:save_photo"
ohos:height="match_content"
ohos:width="match_content"
ohos:background_element="$graphic:background_ability_main"
ohos:layout_alignment="horizontal_center"
ohos:text="保存圖片"
ohos:text_size="20vp"
/>
效果如圖:
涉及權(quán)限
config.json權(quán)限配置如下:
"reqPermissions": [
{"name": "ohos.permission.READ_USER_STORAGE"},
{"name": "ohos.permission.WRITE_USER_STORAGE"}
]
動(dòng)態(tài)申請(qǐng)權(quán)限
需要?jiǎng)討B(tài)申請(qǐng)這兩個(gè)權(quán)限,申請(qǐng)時(shí)會(huì)有權(quán)限彈窗,不寫的話,不會(huì)有權(quán)限彈窗,但是也是可以使用的。
String[] permissions = {"ohos.permission.READ_USER_STORAGE", "ohos.permission.WRITE_USER_STORAGE"};
requestPermissionsFromUser(permissions, 0);
保存圖片
獲取到權(quán)限之后,就可以保存圖片到系統(tǒng)相冊(cè)了,我們媒體的增刪改查都需要用到DataAbilityHelper和AVStorage。
//保存圖片到相冊(cè) fileName文件名 PixelMap 圖片數(shù)據(jù)
private void saveImageToLibrary(String fileName, PixelMap pixelMap) {
try {
ValuesBucket valuesBucket = new ValuesBucket();
//文件名
valuesBucket.putString(AVStorage.Images.Media.DISPLAY_NAME, fileName);
//相對(duì)路徑
valuesBucket.putString("relative_path", "DCIM/");
//文件格式,類型要一定要注意要是JPEG,PNG類型不支持
valuesBucket.putString(AVStorage.Images.Media.MIME_TYPE, "image/JPEG");
//應(yīng)用獨(dú)占:is_pending設(shè)置為1時(shí)表示只有該應(yīng)用能訪問(wèn)此圖片,其他應(yīng)用無(wú)法發(fā)現(xiàn)該圖片,當(dāng)圖片處理操作完成后再吧is_pending設(shè)置為0,解除獨(dú)占,讓其他應(yīng)用可見
valuesBucket.putInteger("is_pending", 1);
//鴻蒙的helper.insert方法和安卓的contentResolver.insert方法有所不同,安卓方法直接返回一個(gè)uri,我們就可以拿來(lái)直接操作,而鴻蒙方法返回官方描述是Returns the index of the inserted data record(返回插入的數(shù)據(jù)記錄的索引),這個(gè)index我的理解就是id,因此,我們需要自己在后面拼出文件的uri再進(jìn)行操作
DataAbilityHelper helper = DataAbilityHelper.creator(this);
int index = helper.insert(AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI, valuesBucket);
Uri uri = Uri.appendEncodedPathToUri(AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI, String.valueOf(index));
//獲取到uri后,安卓通過(guò)contentResolver.openOutputStream(uri)就能獲取到輸出流來(lái)寫文件,而鴻蒙沒有提供這樣的方法,我們就只能通過(guò)uri獲取FileDescriptor,再通過(guò)FileDescriptor生成輸出流打包編碼成新的圖片文件,這里helper.openFile方法一定要有“w”寫模式,不然會(huì)報(bào)FileNotFound的錯(cuò)誤。
FileDescriptor fd = helper.openFile(uri, "w");
ImagePacker imagePacker = ImagePacker.create();
ImagePacker.PackingOptions packingOptions = new ImagePacker.PackingOptions();
OutputStream outputStream = new FileOutputStream(fd);
packingOptions.format = "image/jpeg";
packingOptions.quality = 90;
boolean result = imagePacker.initializePacking(outputStream, packingOptions);
if (result) {
result = imagePacker.addImage(pixelMap);
if (result) {
long dataSize = imagePacker.finalizePacking();
}
}
outputStream.flush();
outputStream.close();
valuesBucket.clear();
//解除獨(dú)占
valuesBucket.putInteger("is_pending", 0);
helper.update(uri, valuesBucket, null);
} catch (Exception e) {
e.printStackTrace();
}
}
效果如下
讀取本地相冊(cè)圖片
在config.json中配置讀取文件權(quán)限(ohos.permission.READ_USER_STORAGE)
"reqPermissions": [{"name": "ohos.permission.READ_USER_STORAGE"}]
在ability中手動(dòng)申請(qǐng)權(quán)限
String[] permissions = {"ohos.permission.READ_USER_STORAGE"};
requestPermissionsFromUser(permissions, 0);
彈出數(shù)據(jù)來(lái)源選擇框,獲取數(shù)據(jù)來(lái)源的方式。
//選擇圖片
private void selectPhoto() {
//調(diào)起系統(tǒng)的選擇來(lái)源數(shù)據(jù)視圖
Intent intent = new Intent();
Operation opt=new Intent.OperationBuilder().withAction("android.intent.action.GET_CONTENT").build();
intent.setOperation(opt);
intent.addFlags(Intent.FLAG_NOT_OHOS_COMPONENT);
intent.setType("image/*");
startAbilityForResult(intent, imgRequestCode);
}
效果如圖:
下面是選擇圖片的回調(diào),imgRequestCode字段的是自定義的,必須是int的類型,這個(gè)字段是和上面的selectPhoto()方法里面的imgRequestCode是一致的,根據(jù)這個(gè)imgRequestCode來(lái)判斷是否從選擇圖片的回調(diào)回來(lái)的,
/*選擇圖片回調(diào)*/
@Override
protected void onAbilityResult(int requestCode, int resultCode, Intent resultData) {
if(requestCode==imgRequestCode && resultData!=null)
{
//選擇的Img對(duì)應(yīng)的Uri
String chooseImgUrl=resultData.getUriString();
//定義數(shù)據(jù)能力幫助對(duì)象
DataAbilityHelper helper=DataAbilityHelper.creator(getContext());
//定義圖片來(lái)源對(duì)象
ImageSource imageSource = null;
//獲取選擇的Img對(duì)應(yīng)的Id
String chooseImgId=null;
//如果是選擇文件則getUriString結(jié)果為dataability:///com.android.providers.media.documents/document/image%3A437,其中%3A437是":"的URL編碼結(jié)果,后面的數(shù)字就是image對(duì)應(yīng)的Id
//如果選擇的是圖庫(kù)則getUriString結(jié)果為dataability:///media/external/images/media/262,最后就是image對(duì)應(yīng)的Id
//這里需要判斷是選擇了文件還是圖庫(kù)
if(chooseImgUri.lastIndexOf("%3A")!=-1){
chooseImgId = chooseImgUri.substring(chooseImgUri.lastIndexOf("%3A")+3);
}
else {
chooseImgId = chooseImgUri.substring(chooseImgUri.lastIndexOf('/')+1);
}
//獲取圖片對(duì)應(yīng)的uri,由于獲取到的前綴是content,我們替換成對(duì)應(yīng)的dataability前綴
Uri uri=Uri.appendEncodedPathToUri(AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI,chooseImgId);
try {
//讀取圖片
FileDescriptor fd = helper.openFile(uri, "r");
imageSource = ImageSource.create(fd, null);
//創(chuàng)建位圖
PixelMap pixelMap = imageSource.createPixelmap(null);
//設(shè)置圖片控件對(duì)應(yīng)的位圖
photo.setPixelMap(pixelMap);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (imageSource != null) {
imageSource.release();
}
}
}
}
總結(jié)
官網(wǎng)現(xiàn)有文檔不多,開發(fā)鴻蒙的時(shí)候遇到很多問(wèn)題,有安卓基礎(chǔ)的小伙伴可以參考安卓的思路去解決,應(yīng)該可以事半功倍,希望本次分享對(duì)大家有所幫助。
??想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):??
??51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)??