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