• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# In-Application HSP Development
2
3An in-application Harmony Shared Package (HSP) is a file used for code and resource sharing within an application (called the host application) and can only be invoked by a HAP or HSP of the same application.
4The in-application 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.
5
6## Developing an In-Application HSP
7
8[Create an HSP module in DevEco Studio](https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/hsp-0000001521396322-V3#section7717162312546). In this example, an HSP module named **library** is created. The basic project directory structure is as follows:
9```
10library
11├── src
12│   └── main
13│       ├── ets
14│       │   ├── pages
15│       │   └── index.ets
16│       ├── resources
17│       └── module.json5
18└── oh-package.json5
19```
20
21### Exporting TS Classes and Methods
22Use **export** to export TS classes and methods. The sample code is as follows:
23```ts
24// library/src/main/ets/utils/test.ts
25export class Log {
26    static info(msg: string) {
27        console.info(msg);
28    }
29}
30
31export function add(a: number, b: number) {
32  return a + b;
33}
34
35export function minus(a: number, b: number) {
36  return a - b;
37}
38```
39In the entry point file **index.ets**, declare the APIs to be exposed.
40```ts
41// library/src/main/ets/index.ets
42export { Log, add, minus } from './utils/test'
43```
44
45### Exporting ArkUI Components
46Use **export** to export ArkUI components. The sample code is as follows:
47```ts
48// library/src/main/ets/components/MyTitleBar.ets
49@Component
50export struct MyTitleBar {
51  build() {
52    Row() {
53      Text($r('app.string.library_title'))
54        .fontColor($r('app.color.white'))
55        .fontSize(25)
56        .margin({left:15})
57    }
58    .width('100%')
59    .height(50)
60    .padding({left:15})
61    .backgroundColor('#0D9FFB')
62  }
63}
64```
65In the entry point file **index.ets**, declare the APIs to be exposed.
66```ts
67// library/src/main/ets/index.ets
68export { MyTitleBar } from './components/MyTitleBar'
69```
70
71### Accessing Resources in an HSP Through $r
72More 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.
73
74In 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).
75
76To avoid reference errors, do not use relative paths. For example, if 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**.
77
78```ts
79// library/src/main/ets/pages/Index.ets
80// Correct
81Image($r("app.media.example"))
82  .width("100%")
83// Incorrect
84Image("../../resources/base/media/example.png")
85  .width("100%")
86```
87
88### Exporting Resources from an HSP
89When 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:
90- You can keep resources well under your control, eliminating the need for exporting resources that do not need to be exposed.
91- 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.
92
93The implementation is as follows:
94
95Implement the **ResManager** class for encapsulating resources to be exported.
96```ts
97// library/src/main/ets/ResManager.ets
98export class ResManager{
99  static getPic(): Resource{
100    return $r("app.media.pic");
101  }
102  static getDesc(): Resource{
103    return $r("app.string.shared_desc");
104  }
105}
106```
107
108In the entry point file **index.ets**, declare the APIs to be exposed.
109```ts
110// library/src/main/ets/index.ets
111export { ResManager } from './ResManager'
112```
113
114### Exporting Native Methods
115The 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 **libnative.so** file is exported.
116```ts
117// library/src/main/ets/utils/nativeTest.ts
118import native from "libnative.so"
119
120export function nativeMulti(a: number, b: number) {
121    let result: number = native.multi(a, b);
122    return result;
123}
124```
125
126In the entry point file **index.ets**, declare the APIs to be exposed.
127```ts
128// library/src/main/ets/index.ets
129export { nativeMulti } from './utils/nativeTest'
130```
131
132## Using the In-Application HSP
133To use APIs in the HSP, first [configure the dependency](https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/hsp-0000001521396322-V3#section6161154819195) on the HSP in the **oh-package.json5** file of the module that needs to call the APIs (called the invoking module).
134You 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**:
135
136```ts
137// library/src/main/ets/index.ets
138export { Log, add, minus } from './utils/test'
139export { MyTitleBar } from './components/MyTitleBar'
140export { ResManager } from './ResManager'
141export { nativeMulti } from './utils/nativeTest'
142```
143The APIs can be used as follows in the code of the invoking module:
144```ts
145// entry/src/main/ets/pages/index.ets
146import { Log, add, MyTitleBar, ResManager, nativeMulti } from "library"
147import { BusinessError } from '@ohos.base';
148
149@Entry
150@Component
151struct Index {
152  @State message: string = 'Hello World'
153  build() {
154    Row() {
155      Column() {
156        MyTitleBar()
157        Text(this.message)
158          .fontSize(30)
159          .fontWeight(FontWeight.Bold)
160        Button('add(1, 2)')
161          .onClick(()=>{
162            Log.info("add button click!");
163            this.message = "result: " + add(1, 2);
164          })
165        // Resource object returned by ResManager, which can be passed to a component for direct use or be extracted.
166        Image(ResManager.getPic())
167          .width("100%")
168        Button('getStringValue')
169          .onClick(()=> {
170            // 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.
171            getContext().createModuleContext('library').resourceManager.getStringValue(ResManager.getDesc())
172              .then(value => {
173                console.log("getStringValue is " + value);
174              })
175              .catch((err: BusinessError) => {
176                console.log("getStringValue promise error is " + error);
177              });
178          })
179          .width("50%")
180        Button('nativeMulti(3, 4)')
181          .onClick(()=>{
182            Log.info("nativeMulti button click!");
183            this.message = "result: " + nativeMulti(3, 4);
184          })
185      }
186      .width('100%')
187    }
188    .height('100%')
189  }
190}
191```
192
193### Redirecting to a Page
194
195If 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/MainAbility/Index.ets** file of the **entry** module:
196```ts
197import router from '@ohos.router';
198import { BusinessError } from '@ohos.base';
199
200@Entry
201@Component
202struct Index {
203    @State message: string = 'Hello World'
204
205    build() {
206    Row() {
207        Column() {
208        Text(this.message)
209            .fontSize(50)
210            .fontWeight(FontWeight.Bold)
211        // Add a button to respond to user clicks.
212        Button() {
213            Text('click to menu')
214            .fontSize(30)
215            .fontWeight(FontWeight.Bold)
216        }
217        .type(ButtonType.Capsule)
218        .margin({
219            top: 20
220        })
221        .backgroundColor('#0D9FFB')
222        .width('40%')
223        .height('5%')
224        // Bind click events.
225        .onClick(() => {
226            router.pushUrl({
227              url: '@bundle:com.example.hmservice/library/ets/pages/menu'
228            }).then(() => {
229              console.log("push page success");
230            }).catch((err: BusinessError) => {
231              console.error(`pushUrl failed, code is ${err.code}, message is ${err.message}`);
232            })
233        })
234      .width('100%')
235    }
236    .height('100%')
237    }
238  }
239}
240```
241The input parameter **url** of the **router.pushUrl** API is as follows:
242```ets
243'@bundle:com.example.hmservice/library/ets/pages/menu'
244```
245The **url** content template is as follows:
246```ets
247'@bundle:bundle name/module name/path/page file name (without the extension .ets)'
248```
249