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