1e41f4b71Sopenharmony_ci# Updating Local and Online Images in the Widget 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci 4e41f4b71Sopenharmony_ciTypically, a widget includes local images or online images downloaded from the network. To obtain local and online images, use the FormExtensionAbility. The following exemplifies how to show local and online images on a widget. 5e41f4b71Sopenharmony_ci 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ci1. For the widget to download online images, declare the **ohos.permission.INTERNET** permission for the widget. For details, see [Declaring Permissions](../security/AccessToken/declare-permissions.md). 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ci2. Update local files in the **onAddForm** lifecycle callback of the EntryFormAbility. 10e41f4b71Sopenharmony_ci 11e41f4b71Sopenharmony_ci ```ts 12e41f4b71Sopenharmony_ci import { Want } from '@kit.AbilityKit'; 13e41f4b71Sopenharmony_ci import { BusinessError } from '@kit.BasicServicesKit'; 14e41f4b71Sopenharmony_ci import { fileIo } from '@kit.CoreFileKit'; 15e41f4b71Sopenharmony_ci import { formBindingData, FormExtensionAbility } from '@kit.FormKit'; 16e41f4b71Sopenharmony_ci import { hilog } from '@kit.PerformanceAnalysisKit'; 17e41f4b71Sopenharmony_ci 18e41f4b71Sopenharmony_ci const TAG: string = 'WgtImgUpdateEntryFormAbility'; 19e41f4b71Sopenharmony_ci const DOMAIN_NUMBER: number = 0xFF00; 20e41f4b71Sopenharmony_ci 21e41f4b71Sopenharmony_ci export default class WgtImgUpdateEntryFormAbility extends FormExtensionAbility { 22e41f4b71Sopenharmony_ci // When the widget is added, a local image is opened and transferred to the widget page for display. 23e41f4b71Sopenharmony_ci onAddForm(want: Want): formBindingData.FormBindingData { 24e41f4b71Sopenharmony_ci // Assume that the local image head.PNG is in the tmp directory of the current widget. 25e41f4b71Sopenharmony_ci let tempDir = this.context.getApplicationContext().tempDir; 26e41f4b71Sopenharmony_ci hilog.info(DOMAIN_NUMBER, TAG, `tempDir: ${tempDir}`); 27e41f4b71Sopenharmony_ci let imgMap: Record<string, number> = {}; 28e41f4b71Sopenharmony_ci try { 29e41f4b71Sopenharmony_ci // Open the local image and obtain the FD after the image is opened. 30e41f4b71Sopenharmony_ci let file = fileIo.openSync(tempDir + '/' + 'head.PNG'); 31e41f4b71Sopenharmony_ci imgMap['imgBear'] = file.fd; 32e41f4b71Sopenharmony_ci } catch (e) { 33e41f4b71Sopenharmony_ci hilog.error(DOMAIN_NUMBER, TAG, `openSync failed: ${JSON.stringify(e as BusinessError)}`); 34e41f4b71Sopenharmony_ci } 35e41f4b71Sopenharmony_ci 36e41f4b71Sopenharmony_ci class FormDataClass { 37e41f4b71Sopenharmony_ci text: string = 'Image: Bear'; 38e41f4b71Sopenharmony_ci loaded: boolean = true; 39e41f4b71Sopenharmony_ci // If an image needs to be displayed in the widget, the value of imgName must be the same as the key 'imgBear' in formImages. 40e41f4b71Sopenharmony_ci imgName: string = 'imgBear'; 41e41f4b71Sopenharmony_ci // If an image needs to be displayed in the widget, the formImages field is mandatory (formImages cannot be left blank or renamed), and 'imgBear' corresponds to the FD. 42e41f4b71Sopenharmony_ci formImages: Record<string, number> = imgMap; 43e41f4b71Sopenharmony_ci } 44e41f4b71Sopenharmony_ci 45e41f4b71Sopenharmony_ci let formData = new FormDataClass(); 46e41f4b71Sopenharmony_ci // Encapsulate the FD in formData and return it to the widget page. 47e41f4b71Sopenharmony_ci return formBindingData.createFormBindingData(formData); 48e41f4b71Sopenharmony_ci } 49e41f4b71Sopenharmony_ci //... 50e41f4b71Sopenharmony_ci } 51e41f4b71Sopenharmony_ci ``` 52e41f4b71Sopenharmony_ci 53e41f4b71Sopenharmony_ci3. Update online files in the **onFormEvent** lifecycle callback of the EntryFormAbility. 54e41f4b71Sopenharmony_ci 55e41f4b71Sopenharmony_ci ```ts 56e41f4b71Sopenharmony_ci import { BusinessError } from '@kit.BasicServicesKit'; 57e41f4b71Sopenharmony_ci import { fileIo } from '@kit.CoreFileKit'; 58e41f4b71Sopenharmony_ci import { formBindingData, FormExtensionAbility, formProvider } from '@kit.FormKit'; 59e41f4b71Sopenharmony_ci import { http } from '@kit.NetworkKit'; 60e41f4b71Sopenharmony_ci import { hilog } from '@kit.PerformanceAnalysisKit'; 61e41f4b71Sopenharmony_ci 62e41f4b71Sopenharmony_ci const TAG: string = 'WgtImgUpdateEntryFormAbility'; 63e41f4b71Sopenharmony_ci const DOMAIN_NUMBER: number = 0xFF00; 64e41f4b71Sopenharmony_ci 65e41f4b71Sopenharmony_ci export default class WgtImgUpdateEntryFormAbility extends FormExtensionAbility { 66e41f4b71Sopenharmony_ci onFormEvent(formId: string, message: string): void { 67e41f4b71Sopenharmony_ci let param: Record<string, string> = { 68e41f4b71Sopenharmony_ci 'text': 'Updating...' 69e41f4b71Sopenharmony_ci }; 70e41f4b71Sopenharmony_ci let formInfo: formBindingData.FormBindingData = formBindingData.createFormBindingData(param); 71e41f4b71Sopenharmony_ci formProvider.updateForm(formId, formInfo); 72e41f4b71Sopenharmony_ci 73e41f4b71Sopenharmony_ci // Note: After being started with the triggering of the lifecycle callback, the FormExtensionAbility can run in the background for only 5 seconds. 74e41f4b71Sopenharmony_ci // When possible, limit the size of the image to download. If an image cannot be downloaded within 5 seconds, it will not be updated to the widget page. 75e41f4b71Sopenharmony_ci let netFile = 'https://cn-assets.gitee.com/assets/mini_app-e5eee5a21c552b69ae6bf2cf87406b59.jpg'; // Specify the URL of the image to download. 76e41f4b71Sopenharmony_ci let tempDir = this.context.getApplicationContext().tempDir; 77e41f4b71Sopenharmony_ci let fileName = 'file' + Date.now(); 78e41f4b71Sopenharmony_ci let tmpFile = tempDir + '/' + fileName; 79e41f4b71Sopenharmony_ci 80e41f4b71Sopenharmony_ci let httpRequest = http.createHttp() 81e41f4b71Sopenharmony_ci httpRequest.request(netFile).then((data) => { 82e41f4b71Sopenharmony_ci if (data?.responseCode == http.ResponseCode.OK) { 83e41f4b71Sopenharmony_ci let imgFile = fileIo.openSync(tmpFile, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE); 84e41f4b71Sopenharmony_ci fileIo.write(imgFile.fd, data.result as ArrayBuffer).then((writeLen: number) => { 85e41f4b71Sopenharmony_ci hilog.info(DOMAIN_NUMBER, TAG, "write data to file succeed and size is:" + writeLen); 86e41f4b71Sopenharmony_ci }).catch((err: BusinessError) => { 87e41f4b71Sopenharmony_ci hilog.error(DOMAIN_NUMBER, TAG, "write data to file failed with error message: " + err.message + ", error code: " + err.code); 88e41f4b71Sopenharmony_ci }).finally(() => { 89e41f4b71Sopenharmony_ci fileIo.closeSync(imgFile); 90e41f4b71Sopenharmony_ci }); 91e41f4b71Sopenharmony_ci 92e41f4b71Sopenharmony_ci hilog.info(DOMAIN_NUMBER, TAG, 'ArkTSCard download complete: %{public}s', tmpFile); 93e41f4b71Sopenharmony_ci let imgMap: Record<string, number> = {}; 94e41f4b71Sopenharmony_ci try { 95e41f4b71Sopenharmony_ci let file = fileIo.openSync(tmpFile); 96e41f4b71Sopenharmony_ci imgMap[fileName] = file.fd; 97e41f4b71Sopenharmony_ci } catch (e) { 98e41f4b71Sopenharmony_ci hilog.error(DOMAIN_NUMBER, TAG, `openSync failed: ${JSON.stringify(e as BusinessError)}`); 99e41f4b71Sopenharmony_ci } 100e41f4b71Sopenharmony_ci 101e41f4b71Sopenharmony_ci class FormDataClass { 102e41f4b71Sopenharmony_ci text: string = 'Image: Bear' + fileName; 103e41f4b71Sopenharmony_ci loaded: boolean = true; 104e41f4b71Sopenharmony_ci // If an image needs to be displayed in the widget, the value of imgName must be the same as the key fileName in formImages. 105e41f4b71Sopenharmony_ci imgName: string = fileName; 106e41f4b71Sopenharmony_ci // If an image needs to be displayed in the widget, the formImages field is mandatory (formImages cannot be left blank or renamed), and fileName corresponds to the FD. 107e41f4b71Sopenharmony_ci formImages: Record<string, number> = imgMap; 108e41f4b71Sopenharmony_ci } 109e41f4b71Sopenharmony_ci 110e41f4b71Sopenharmony_ci let formData = new FormDataClass(); 111e41f4b71Sopenharmony_ci let formInfo = formBindingData.createFormBindingData(formData); 112e41f4b71Sopenharmony_ci formProvider.updateForm(formId, formInfo).then(() => { 113e41f4b71Sopenharmony_ci hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'FormAbility updateForm success.'); 114e41f4b71Sopenharmony_ci }).catch((error: BusinessError) => { 115e41f4b71Sopenharmony_ci hilog.error(DOMAIN_NUMBER, TAG, `FormAbility updateForm failed: ${JSON.stringify(error)}`); 116e41f4b71Sopenharmony_ci }); 117e41f4b71Sopenharmony_ci } else { 118e41f4b71Sopenharmony_ci hilog.error(DOMAIN_NUMBER, TAG, `ArkTSCard download task failed`); 119e41f4b71Sopenharmony_ci let param: Record<string, string> = { 120e41f4b71Sopenharmony_ci 'text': 'Update failed.' 121e41f4b71Sopenharmony_ci }; 122e41f4b71Sopenharmony_ci let formInfo: formBindingData.FormBindingData = formBindingData.createFormBindingData(param); 123e41f4b71Sopenharmony_ci formProvider.updateForm(formId, formInfo); 124e41f4b71Sopenharmony_ci } 125e41f4b71Sopenharmony_ci httpRequest.destroy(); 126e41f4b71Sopenharmony_ci }) 127e41f4b71Sopenharmony_ci } 128e41f4b71Sopenharmony_ci //... 129e41f4b71Sopenharmony_ci } 130e41f4b71Sopenharmony_ci ``` 131e41f4b71Sopenharmony_ci 132e41f4b71Sopenharmony_ci4. On the widget page, use the **backgroundImage** attribute to display the widget content passed from the EntryFormAbility. 133e41f4b71Sopenharmony_ci 134e41f4b71Sopenharmony_ci ```ts 135e41f4b71Sopenharmony_ci let storageWidgetImageUpdate = new LocalStorage(); 136e41f4b71Sopenharmony_ci 137e41f4b71Sopenharmony_ci @Entry(storageWidgetImageUpdate) 138e41f4b71Sopenharmony_ci @Component 139e41f4b71Sopenharmony_ci struct WidgetImageUpdateCard { 140e41f4b71Sopenharmony_ci @LocalStorageProp('text') text: ResourceStr = $r('app.string.loading'); 141e41f4b71Sopenharmony_ci @LocalStorageProp('loaded') loaded: boolean = false; 142e41f4b71Sopenharmony_ci @LocalStorageProp('imgName') imgName: ResourceStr = $r('app.string.imgName'); 143e41f4b71Sopenharmony_ci 144e41f4b71Sopenharmony_ci build() { 145e41f4b71Sopenharmony_ci Column() { 146e41f4b71Sopenharmony_ci Column() { 147e41f4b71Sopenharmony_ci Text(this.text) 148e41f4b71Sopenharmony_ci .fontColor('#FFFFFF') 149e41f4b71Sopenharmony_ci .opacity(0.9) 150e41f4b71Sopenharmony_ci .fontSize(12) 151e41f4b71Sopenharmony_ci .textOverflow({ overflow: TextOverflow.Ellipsis }) 152e41f4b71Sopenharmony_ci .maxLines(1) 153e41f4b71Sopenharmony_ci .margin({ top: '8%', left: '10%' }) 154e41f4b71Sopenharmony_ci }.width('100%').height('50%') 155e41f4b71Sopenharmony_ci .alignItems(HorizontalAlign.Start) 156e41f4b71Sopenharmony_ci 157e41f4b71Sopenharmony_ci Row() { 158e41f4b71Sopenharmony_ci Button() { 159e41f4b71Sopenharmony_ci Text($r('app.string.update')) 160e41f4b71Sopenharmony_ci .fontColor('#45A6F4') 161e41f4b71Sopenharmony_ci .fontSize(12) 162e41f4b71Sopenharmony_ci } 163e41f4b71Sopenharmony_ci .width(120) 164e41f4b71Sopenharmony_ci .height(32) 165e41f4b71Sopenharmony_ci .margin({ top: '30%', bottom: '10%' }) 166e41f4b71Sopenharmony_ci .backgroundColor('#FFFFFF') 167e41f4b71Sopenharmony_ci .borderRadius(16) 168e41f4b71Sopenharmony_ci .onClick(() => { 169e41f4b71Sopenharmony_ci postCardAction(this, { 170e41f4b71Sopenharmony_ci action: 'message', 171e41f4b71Sopenharmony_ci params: { 172e41f4b71Sopenharmony_ci info: 'refreshImage' 173e41f4b71Sopenharmony_ci } 174e41f4b71Sopenharmony_ci }); 175e41f4b71Sopenharmony_ci }) 176e41f4b71Sopenharmony_ci }.width('100%').height('40%') 177e41f4b71Sopenharmony_ci .justifyContent(FlexAlign.Center) 178e41f4b71Sopenharmony_ci } 179e41f4b71Sopenharmony_ci .width('100%').height('100%') 180e41f4b71Sopenharmony_ci .backgroundImage(this.loaded ? 'memory://' + this.imgName : $r('app.media.ImageDisp')) 181e41f4b71Sopenharmony_ci .backgroundImageSize(ImageSize.Cover) 182e41f4b71Sopenharmony_ci } 183e41f4b71Sopenharmony_ci } 184e41f4b71Sopenharmony_ci ``` 185e41f4b71Sopenharmony_ci 186e41f4b71Sopenharmony_ci> **NOTE** 187e41f4b71Sopenharmony_ci> 188e41f4b71Sopenharmony_ci> - The **\<Image>** component displays images in the remote memory based on the **memory://** identifier in the input parameter (**memory://fileName**). The value of **fileName** must be consistent with the key in the object (**'formImages': {key: fd}**) passed by the EntryFormAbility. 189e41f4b71Sopenharmony_ci> 190e41f4b71Sopenharmony_ci> - The **\<Image>** component determines whether to update the image by comparing the values of **imgName** consecutively passed by the EntryFormAbility. It updates the image only when the values are different. 191