1# HSP 2 3A Harmony Shared Package (HSP) is a dynamic shared package that can contain code, C++ libraries, resource files, and configuration files (also called profiles) and allows for code and resource sharing. An HSP is released with the Application Package (App Pack) of the host application, shares a process with the host application, and has the same bundle name and lifecycle as the host application. 4> **NOTE** 5> 6> In-app HSP: a type of HSP that is closely coupled with an application bundle name (**bundleName**) during compilation and can be used only by the specified application. 7> 8> [Integrated HSP](integrated-hsp.md): a type of HSP that is not coupled with any specific application bundle name during the build and release processes and whose bundle name can be automatically replaced by the toolchain with the host application bundle name. 9 10## Use Scenarios 11- By storing code and resource files shared by multiple HAPs/HSPs in one place, the HSP significantly improves the reusability and maintainability of the code and resource files. Better yet, because only one copy of the HSP code and resource files is retained during building and packaging, the size of the application package is effectively controlled. 12 13- The HSP is loaded on demand during application running, which helps improve application performance. 14 15- The integrated HSP allows for code and resource sharing across applications in the same organization. 16 17## Constraints 18 19- An HSP must be installed and run with the HAP that depends on it. It cannot be installed or run independently on a device. The version of an HSP must be the same as that of the HAP. 20- An HSP does not support the declaration of the [ExtensionAbility](../application-models/extensionability-overview.md) component in the configuration file, but supports the [UIAbility](../application-models/uiability-overview.md) component. 21- An HSP can depend on other HARs or HSPs, but does not support cyclic dependency or dependency transfer. 22 23 24## Creating an HSP 25Create an HSP module in DevEco Studio. For details, see <!--RP1-->[Creating an HSP Module](https://developer.huawei.com/consumer/en/doc/harmonyos-guides-V5/ide-hsp-V5#section7717162312546)<!--RP1End-->. The following describes how to create an HSP module named **library**. The basic project directory structure is as follows: 26``` 27MyApplication 28├── library 29│ ├── src 30│ │ └── main 31│ │ ├── ets 32│ │ │ └── pages 33│ │ │ └── index.ets 34│ │ ├── resources 35│ │ └── module.json5 36│ ├── oh-package.json5 37│ ├── index.ets 38│ └── build-profile.json5 // Module-level configuration file 39└── build-profile.json5 // Project-level configuration file 40``` 41 42## Developing an HSP 43 44 45You can export the ArkUI components, APIs, and other resources of an HSP for other HAPs or HSPs in the same application to reference. 46 47### Exporting ArkUI Components 48Use **export** to export ArkUI components. The sample code is as follows: 49```ts 50// library/src/main/ets/components/MyTitleBar.ets 51@Component 52export struct MyTitleBar { 53 build() { 54 Row() { 55 Text($r('app.string.library_title')) 56 .id('library') 57 .fontFamily('HarmonyHeiTi') 58 .fontWeight(FontWeight.Bold) 59 .fontSize(32) 60 .fontColor($r('app.color.text_color')) 61 } 62 .width('100%') 63 } 64} 65``` 66In the entry point file **index.ets**, declare the APIs to be exposed. 67```ts 68// library/index.ets 69export { MyTitleBar } from './src/main/ets/components/MyTitleBar'; 70``` 71 72 73### Exporting TS Classes and Methods 74Use **export** to export TS classes and methods. The sample code is as follows: 75```ts 76// library/src/main/ets/utils/test.ets 77export class Log { 78 static info(msg: string): void { 79 console.info(msg); 80 } 81} 82 83export function add(a: number, b: number): number { 84 return a + b; 85} 86 87export function minus(a: number, b: number): number { 88 return a - b; 89} 90``` 91In the entry point file **index.ets**, declare the APIs to be exposed. 92```ts 93// library/index.ets 94export { Log, add, minus } from './src/main/ets/utils/test'; 95``` 96### Exporting Native Methods 97The HSP can contain .so files compiled in C++. The HSP indirectly exports the native method in the .so file. In this example, the **multi** API in the **liblibrary.so** file is exported. 98```ts 99// library/src/main/ets/utils/nativeTest.ets 100import native from 'liblibrary.so'; 101 102export function nativeMulti(a: number, b: number): number { 103 let result: number = native.multi(a, b); 104 return result; 105} 106``` 107 108In the entry point file **index.ets**, declare the APIs to be exposed. 109```ts 110// library/index.ets 111export { nativeMulti } from './src/main/ets/utils/nativeTest'; 112``` 113 114### Accessing Resources in an HSP Through $r 115More often than not, you may need to use resources, such as strings and images, in components. For components in an HSP, such resources are typically placed in the HSP package, rather than in the package where the HSP is invoked, for the purpose of complying with the principle of high cohesion and low coupling. 116 117In a project, application resources are referenced in the $r/$rawfile format. You can use **$r**/**$rawfile** to access resources in the **resources** directory of the current module. For example, you can use **$r("app.media.example")** to access the **src/main/resources/base/media/example.png** image stored in the **resources** directory. For details about how to use **$r**/**$rawfile**, see [Resource Access: Application Resources](./resource-categories-and-access.md#application-resources). 118 119To avoid reference errors, do not use relative paths. For example, 120if you use **Image("../../resources/base/media/example.png")**, the image actually used will be the one in the directory of the module that invokes the HSP. That is, if the module that invokes the HSP is **entry**, then the image used will be **entry/src/main/resources/base/media/example.png**. 121 122```ts 123// library/src/main/ets/pages/Index.ets 124// Correct 125Image($r('app.media.example')) 126 .id('example') 127 .borderRadius('48px') 128// Incorrect 129Image("../../resources/base/media/example.png") 130 .id('example') 131 .borderRadius('48px') 132``` 133 134### Exporting Resources from HSP 135When resources in an HSP need to be exported for cross-package access, it is recommended that a resource manager class be implemented to encapsulate the exported resources. In this way: 136- You can keep resources well under your control, eliminating the need for exporting resources that do not need to be exposed. 137- The invoking module does not need to be aware of the internal resource names of the HSP, or make adaptation to changes in these internal resource names. 138 139The implementation is as follows: 140 141Encapsulate the resources that need to be published into a resource management class. 142```ts 143// library/src/main/ets/ResManager.ets 144export class ResManager{ 145 static getPic(): Resource{ 146 return $r('app.media.pic'); 147 } 148 static getDesc(): Resource{ 149 return $r('app.string.shared_desc'); 150 } 151} 152``` 153 154In the entry point file **index.ets**, declare the APIs to be exposed. 155```ts 156// library/index.ets 157export { ResManager } from './src/main/ets/ResManager'; 158``` 159 160 161 162## Using an HSP 163 164You can reference APIs in an HSP and implement page redirection in the HSP through page routing. 165 166### Referencing APIs 167To use HSP APIs, you need to configure the dependency on HSP APIs in **oh-package.json5**. For details, see <!--RP2-->[Referencing a Shared Package](https://developer.huawei.com/consumer/en/doc/harmonyos-guides-V5/ide-har-import-V5)<!--RP2End-->. 168You can then call the external APIs of the HSP in the same way as calling the APIs in the HAR. In this example, the external APIs are the following ones exported from **library**: 169 170```ts 171// library/index.ets 172export { Log, add, minus } from './src/main/ets/utils/test'; 173export { MyTitleBar } from './src/main/ets/components/MyTitleBar'; 174export { ResManager } from './src/main/ets/ResManager'; 175export { nativeMulti } from './src/main/ets/utils/nativeTest'; 176``` 177The APIs can be used as follows in the code of the invoking module: 178```ts 179// entry/src/main/ets/pages/index.ets 180import { Log, add, MyTitleBar, ResManager, nativeMulti } from 'library'; 181import { BusinessError } from '@ohos.base'; 182import router from '@ohos.router'; 183 184const TAG = 'Index'; 185 186@Entry 187@Component 188struct Index { 189 @State message: string = ''; 190 191 build() { 192 Column() { 193 List() { 194 ListItem() { 195 MyTitleBar() 196 } 197 .margin({ left: '35px', top: '32px' }) 198 199 ListItem() { 200 Text(this.message) 201 .fontFamily('HarmonyHeiTi') 202 .fontSize(18) 203 .textAlign(TextAlign.Start) 204 .width('100%') 205 .fontWeight(FontWeight.Bold) 206 } 207 .width('685px') 208 .margin({ top: 30, bottom: 10 }) 209 210 ListItem() { 211 // Resource object returned by ResManager, which can be passed to a component for direct use or be extracted. 212 Image(ResManager.getPic()) 213 .id('image') 214 .borderRadius('48px') 215 } 216 .width('685px') 217 .margin({ top: 10, bottom: 10 }) 218 .padding({ left: 12, right: 12, top: 4, bottom: 4 }) 219 220 ListItem() { 221 Text($r('app.string.add')) 222 .fontSize(18) 223 .textAlign(TextAlign.Start) 224 .width('100%') 225 .fontWeight(500) 226 .height('100%') 227 } 228 .id('add') 229 .borderRadius(24) 230 .width('685px') 231 .height('84px') 232 .backgroundColor($r('sys.color.ohos_id_color_foreground_contrary')) 233 .margin({ top: 10, bottom: 10 }) 234 .padding({ left: 12, right: 12, top: 4, bottom: 4 }) 235 .onClick(() => { 236 Log.info('add button click!'); 237 this.message = 'result: ' + add(1, 2); 238 }) 239 240 ListItem() { 241 Text($r('app.string.get_string_value')) 242 .fontSize(18) 243 .textAlign(TextAlign.Start) 244 .width('100%') 245 .fontWeight(500) 246 .height('100%') 247 } 248 .id('getStringValue') 249 .borderRadius(24) 250 .width('685px') 251 .height('84px') 252 .backgroundColor($r('sys.color.ohos_id_color_foreground_contrary')) 253 .margin({ top: 10, bottom: 10 }) 254 .padding({ left: 12, right: 12, top: 4, bottom: 4 }) 255 .onClick(() => { 256 // Obtain the context of the HSP module based on the current context, obtain the resourceManager object of the HSP module, and then call the API of resourceManager to obtain resources. 257 getContext() 258 .createModuleContext('library') 259 .resourceManager 260 .getStringValue(ResManager.getDesc()) 261 .then(value => { 262 console.log('getStringValue is ' + value); 263 this.message = 'getStringValue is ' + value; 264 }) 265 .catch((err: BusinessError) => { 266 console.error('getStringValue promise error is ' + err); 267 }); 268 }) 269 270 ListItem() { 271 Text($r('app.string.native_multi')) 272 .fontSize(18) 273 .textAlign(TextAlign.Start) 274 .width('100%') 275 .fontWeight(500) 276 .height('100%') 277 } 278 .id('nativeMulti') 279 .borderRadius(24) 280 .width('685px') 281 .height('84px') 282 .backgroundColor($r('sys.color.ohos_id_color_foreground_contrary')) 283 .margin({ top: 10, bottom: 10 }) 284 .padding({ left: 12, right: 12, top: 4, bottom: 4 }) 285 .onClick(() => { 286 Log.info('nativeMulti button click!'); 287 this.message = 'result: ' + nativeMulti(3, 4); 288 }) 289 } 290 .alignListItem(ListItemAlign.Center) 291 } 292 .width('100%') 293 .backgroundColor($r('app.color.page_background')) 294 .height('100%') 295 } 296} 297``` 298 299### Redirecting to a Page 300 301If you want to add a button in the **entry** module to jump to the menu page (**library/src/main/ets/pages/menu.ets**) in the **library** module, you can write the following code in the **entry/src/main/ets/pages/Index.ets** file of the **entry** module: 302```ts 303import { Log, add, MyTitleBar, ResManager, nativeMulti } from 'library'; 304import { BusinessError } from '@ohos.base'; 305import router from '@ohos.router'; 306 307const TAG = 'Index'; 308 309@Entry 310@Component 311struct Index { 312 @State message: string = ''; 313 314 build() { 315 Column() { 316 List() { 317 ListItem() { 318 Text($r('app.string.click_to_menu')) 319 .fontSize(18) 320 .textAlign(TextAlign.Start) 321 .width('100%') 322 .fontWeight(500) 323 .height('100%') 324 } 325 .id('clickToMenu') 326 .borderRadius(24) 327 .width('685px') 328 .height('84px') 329 .backgroundColor($r('sys.color.ohos_id_color_foreground_contrary')) 330 .margin({ top: 10, bottom: 10 }) 331 .padding({ left: 12, right: 12, top: 4, bottom: 4 }) 332 .onClick(() => { 333 router.pushUrl({ 334 url: '@bundle:com.samples.hspsample/library/ets/pages/Menu' 335 }).then(() => { 336 console.log('push page success'); 337 }).catch((err: BusinessError) => { 338 console.error('pushUrl failed, code is' + err.code + ', message is' + err.message); 339 }) 340 }) 341 } 342 .alignListItem(ListItemAlign.Center) 343 } 344 .width('100%') 345 .backgroundColor($r('app.color.page_background')) 346 .height('100%') 347 } 348} 349``` 350The input parameter **url** of the **router.pushUrl** API is as follows: 351```ets 352'@bundle:com.samples.hspsample/library/ets/pages/Menu' 353``` 354The **url** content template is as follows: 355```ets 356'@bundle:bundleName/moduleName/path/page file name (without the extension .ets)' 357``` 358### Going Back to the Previous Page Using router.back() 359You can use the **router.back** method to go back, from a page in the HSP, to the previous page, under the prerequisite that the target page is in the redirection path of the source page. 360```ts 361import router from '@ohos.router'; 362 363@Entry 364@Component 365struct Index3 { // The path is library/src/main/ets/pages/Back.ets. 366 @State message: string = 'HSP back page'; 367 368 build() { 369 Row() { 370 Column() { 371 Text(this.message) 372 .fontFamily('HarmonyHeiTi') 373 .fontWeight(FontWeight.Bold) 374 .fontSize(32) 375 .fontColor($r('app.color.text_color')) 376 .margin({ top: '32px' }) 377 .width('624px') 378 379 Button($r('app.string.back_to_HAP')) 380 .id('backToHAP') 381 .fontFamily('HarmonyHeiTi') 382 .height(48) 383 .width('624px') 384 .margin({ top: 550 }) 385 .type(ButtonType.Capsule) 386 .borderRadius($r('sys.float.ohos_id_corner_radius_button')) 387 .backgroundColor($r('app.color.button_background')) 388 .fontColor($r('sys.color.ohos_id_color_foreground_contrary')) 389 .fontSize($r('sys.float.ohos_id_text_size_button1')) 390 // Bind click events. 391 .onClick(() => { 392 router.back({ // Go back to the HAP page. 393 url: 'pages/Index' // The path is entry/src/main/ets/pages/Index.ets. 394 }) 395 }) 396 397 Button($r('app.string.back_to_HSP')) 398 .id('backToHSP') 399 .fontFamily('HarmonyHeiTi') 400 .height(48) 401 .width('624px') 402 .margin({ top: '4%' , bottom: '6%' }) 403 .type(ButtonType.Capsule) 404 .borderRadius($r('sys.float.ohos_id_corner_radius_button')) 405 .backgroundColor($r('app.color.button_background')) 406 .fontColor($r('sys.color.ohos_id_color_foreground_contrary')) 407 .fontSize($r('sys.float.ohos_id_text_size_button1')) 408 // Bind click events. 409 .onClick(() => { 410 router.back({ // Go back to the HSP page. 411 url: '@bundle:com.samples.hspsample/library/ets/pages/Menu' // The path is library/src/main/ets/pages/Menu.ets. 412 }) 413 }) 414 } 415 .width('100%') 416 } 417 .backgroundColor($r('app.color.page_background')) 418 .height('100%') 419 } 420} 421``` 422 423The **url** parameter in the **router.back** method is described as follows: 424 425* In this example, the URL for going back from the HSP page to the HAP page is as follows: 426 427 ```ets 428 'pages/Index' 429 ``` 430 The **url** content template is as follows: 431 ```ets 432 'Page file name (without the extension .ets) 433 ``` 434 435* To return to the HSP1 page after switching to the HSP2 page, the URL should be as follows: 436 437 ```ets 438 '@bundle:com.samples.hspsample/library/ets/pages/Menu' 439 ``` 440 The **url** content template is as follows: 441 ```ets 442 '@bundle:bundleName/moduleName/path/page file name (without the extension .ets)' 443 ``` 444