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