在卡片上展示网络图片时,由于卡片环境的限制,无法直接使用网络图片URL。需要先将网络图片下载到本地沙箱,然后通过Image组件显示。
常见的场景包括:

由于ArkTS卡片不支持直接使用网络相关路径,如果需要在卡片上展示网络图片,则需要先将网络图片下载至本地沙箱,然后Image组件通过入参(memory://fileName)中的(memory://)标识来进行远端内存图片显示。
下载网络图片需要使用网络能力,申请ohos.permission.INTERNET权限,配置方式为在module.json5配置文件的requestPermissions标签中声明权限:
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
] 不同场景均需要通过httpRequest.request方法下载网络资源,在下载完成的回调中调用updateForm接口更新图片数据。
class FormDataClass { // 卡片需要显示图片场景,必须和下列字段formImages中的key相同 imgName: string = ''; // 卡片需要显示图片场景,必填字段(formImages不可缺省或改名),fileName对应fd formImages: Record<string, number> = {}; } // 下载文件 download(context: Context, formId: string ) { let netFile = 'https://XXXX'; // 网络图片地址 let httpRequest = http.createHttp() let tempDir = context.getApplicationContext().tempDir; let fileName = 'file' + Date.now(); let tmpFile = tempDir + '/' + fileName; let imgFile = undefined let imgMap: Record<string, number> = {}; // 下载网络资源 httpRequest.request(netFile).then((data) => { if (data?.responseCode === http.ResponseCode.OK) { try { let imgFile = fileIo.openSync(tmpFile, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE); imgMap[fileName] = imgFile.fd; try { fileIo.write(imgFile.fd, data.result as ArrayBuffer).then((writeLen) => { console.info('write data to file succeed and size is:' + writeLen); try { let formData: FormDataClass = { imgName: fileName, formImages: imgMap } const formInfo = formBindingData.createFormBindingData(formData) formProvider.updateForm(formId, formInfo).then(() => { console.info('FormAbility updateForm success.'); }).catch((e: BusinessError) => { console.error(`FormAbility updateForm failed: 63 ${JSON.stringify(e)}`); }); } catch (error) { console.error(`FormAbility updateForm failed: ${JSON.stringify(error)}`); } }) } catch (err) { console.error('write data to file failed with error message: ' + err.message + ', error code: ' + err.code); } } catch (e) { console.error(`openSync failed: ${JSON.stringify(e as BusinessError)}`); } finally { // 在fileIo.closeSync执行之前,确保formProvider.updateForm已执行完毕。 fileIo.closeSync(imgFile); } } else { console.error(`ArkTSCard download task failed`); let param: Record<string, string> = { 'text': '刷新失败' }; const formInfo = (formBindingData.createFormBindingData(param)) formProvider.updateForm(formId, formInfo); } httpRequest.destroy(); }) }
在WidgetCard卡片页面中使用LocalStorageProp装饰需要刷新的卡片数据,使用Image组件加载远端内存图片。
@Entry @Component struct WidgetCard { @LocalStorageProp('imgName') imgName: string = ''; build() { Column() { Image('memory://' + this.imgName) .width(100) } .width('100%') .height('100%') } }
不同场景的区别在于下载网络图片的时机,具体区分为以下四种场景。

创建卡片时,onAddForm是卡片提供方接收创建卡片的通知接口。网络图片下载涉及异步场景,在onAddForm回调返回的卡片数据中暂时无法立即拿到图片资源的信息,需要在图片下载完成的回调中调用updateForm接口,主动刷新网络图片信息。
onAddForm(want: Want): formBindingData.FormBindingData { let formId = want?.parameters?.[formInfo.FormParam.IDENTITY_KEY] as string; // 执行download下载网络图片 this.download(this.context, formId) let formData = new FormDataClass(); return formBindingData.createFormBindingData(formData); }
效果预览:


已上桌的卡片,在主应用内可通过formProvider.getPublishedRunningFormInfos接口获取所有已加桌的卡片信息。接着,通过卡片名称可以过滤出需要更新的目标卡片信息。最后下载网络图片到本地,通过updateForm接口更新卡片的图片。
Button('更新桌面网络图片').onClick(async (event: ClickEvent) => { const context = this.getUIContext().getHostContext() as common.UIAbilityContext // 获取上已上桌的卡片 try { formProvider.getPublishedRunningFormInfos().then((data: formInfo.RunningFormInfo[]) => { console.info(`formProvider getPublishedRunningFormInfos, data: ${JSON.stringify(data)}`); data.forEach((form) => { let formId = form.formId let formName = form.formName // 可根据名称作为条件进行过滤 this.download(context, formId) }) }).catch((error: BusinessError) => { console.error(`promise error, code: ${error.code}, message: ${error.message})`); }); } catch (error) { console.error(`catch error, code: ${(error as BusinessError).code}, message: ${(error as BusinessError).message})`); } })
效果预览:


已上桌的卡片,在卡片可以通过postCardAction接口触发message事件拉起FormExtensionAbility,通过onFormEvent接口回调通知,以完成点击卡片控件后刷新卡片中图片的功能。步骤参考如下:
Button('更新图片').onClick((event: ClickEvent) => { postCardAction(this, { action: 'message', params: { msgTest: 'messageEvent' } }); })
onFormEvent(formId: string, message: string) { this.download(this.context,formId) }
效果预览:


已上桌的卡片,可以在form_config.json配置文件的updateDuration字段中配置定时刷新间隔,也可以配置scheduledUpdateTime字段设置卡片定点刷新时间。在触发定点刷新后,系统会调用FormExtensionAbility的onUpdateForm生命周期回调,在回调中,通过updateForm接口更新卡片的图片。以卡片定点刷新为例,步骤参考如下:
"updateEnabled": true,
"scheduledUpdateTime": "14:21",
"updateDuration": 0, onUpdateForm(formId: string, message: string) { this.download(this.context,formId) }
效果预览:

Q:下载网络图片至沙箱,卡片加载图片失败可能是什么原因导致?
A:卡片中Image组件通过入参(memory://fileName)中的(memory://)标识来进行远端内存图片显示。网络资源在下载过程中,仍可通过openSync打开并获取文件fd。因此,显示卡片时需要确保网络图片已经在沙箱下载完成,避免网络图片下载过程中将fd传递至卡片,造成卡片图片加载失败。
Q:为什么修改传递给卡片formImages中imgName对应的文件fd,卡片中的图片没有更新?
A:Image组件通过传入的参数是否有变化来决定是否刷新图片,因此EntryFormAbility每次传递过来的imgName都需要不同,连续传递两个相同的imgName时,图片不会刷新。
Q:在卡片上展示的图片有什么限制?
A:在卡片刷新过程中,卡片UI通过@LocalStorageProp接收卡片数据时,FormBindingData对象会序列化,即卡片数据会转换成string类型。从API version 20开始,图片文件数量上限为20张,所有图片总内存大小不超过10MB,超出限制的图片会显示异常,API version 19及之前的版本,图片文件数量上限为5张,每张限制内存2MB。
场景 | 描述 | 注意点 |
|---|---|---|
创建卡片时直接展示网络图片 | 桌面创建卡片时,直接加载网络图片。 | 创建卡片时触发onAddForm生命周期,但是由于下载网络图片存在延迟,因此需要先返回默认数据。 |
主应用中主动刷新卡片中网络图片 | 主应用下载网络图片,同步至卡片。 | 应用内获取已上桌卡片可通过首选项或者formProvider.getPublishedRunningFormInfos接口,更新时需要过滤具体的卡片。 |
卡片主动刷新网络图片 | 已上桌卡片自动触发更新。 | 桌面卡片通过发送message事件即可触发FormExtensionAbility的onFormEvent生命周期回调。 |
定时/定点被动刷新卡片中网络图片 | 已上桌卡片定时/定点被动刷新。 | 定时/定点刷新需要在form_config.json中进行配置,且卡片定时/定点刷新频率和优先级存在约束与限制。 |