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