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