• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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