in-app-hsp.md 7.6 KB
Newer Older
J
jsjzju 已提交
1 2 3
# 应用内HSP开发指导

应用内`HSP`指的是专门为某一应用开发的`HSP`,只能被该应用内部其他`HAP`/`HSP`使用,用于应用内部代码、资源的共享。
J
junyi233 已提交
4
应用内`HSP`跟随其宿主应用的APP包一起发布,与宿主应用同进程,具有相同的包名和生命周期。
J
jsjzju 已提交
5 6 7

## 开发应用内HSP

J
junyi233 已提交
8
通过DevEco Studio创建一个HSP模块,创建方式可[参考](https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/hsp-0000001521396322-V3#section7717162312546),我们以创建一个名为`library``HSP`模块为例。基本的工程目录结构大致如下:
J
jsjzju 已提交
9 10 11 12 13 14 15 16 17
```
library
├── src
│   └── main
│       ├── ets
│       │   ├── pages
│       │   └── index.ets
│       ├── resources
│       └── module.json5
Y
yangmingliang 已提交
18
└── oh-package.json5
J
jsjzju 已提交
19 20 21 22 23 24 25 26
```
模块`module.json5`中的`"type"`标识模块类型,`HSP``"type"``"shared"`
```json
{
    "type": "shared"
}
```

Y
yangmingliang 已提交
27
`HSP`通过在入口文件中导出接口,对外提供能力。入口文件在模块`oh-package.json5``"main"`中配置。例如:
J
jsjzju 已提交
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
```json
{
    "main": "./src/main/ets/index.ets"
}
```

### 导出ts类和方法
通过`export`导出ts类和方法,例如:
```ts
// library/src/main/ets/utils/test.ts
export class Log {
    static info(msg) {
        console.info(msg);
    }
}

export function add(a: number, b: number) {
  return a + b;
}

export function minus(a: number, b: number) {
  return a - b;
}
```
对外暴露的接口,需要在入口文件`index.ets`中声明:
```ts
// library/src/main/ets/index.ets
export { Log, add, minus } from './utils/test'
```

### 导出ArkUI组件
ArkUI组件也可以通过`export`导出,例如:
```ts
// library/src/main/ets/components/MyTitleBar.ets
@Component
export struct MyTitleBar {
  build() {
    Row() {
      Text($r('app.string.library_title'))
        .fontColor($r('app.color.white'))
        .fontSize(25)
        .margin({left:15})
    }
    .width('100%')
    .height(50)
    .padding({left:15})
    .backgroundColor('#0D9FFB')
  }
}
```
对外暴露的接口,需要在入口文件`index.ets`中声明:
```ts
// library/src/main/ets/index.ets
export { MyTitleBar } from './components/MyTitleBar'
```
H
Haoming Luo 已提交
83 84 85

### 导出HSP中资源
#### 通过$r访问HSP中资源
J
jsjzju 已提交
86 87 88 89
注意,在`HSP`中,通过`$r`/`$rawfile`可以使用本模块`resources`目录下的资源。
如果使用相对路径的方式,例如:
`HSP`模块中使用`Image("common/example.png")`,实际上该`Image`组件访问的是`HSP调用方`(如`entry`)下的资源`entry/src/main/ets/common/example.png`

H
Haoming Luo 已提交
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
#### 通过resourceManager访问HSP中资源
先通过当前上下文获取hsp模块的上下文,再获取hsp模块的resourceManager,然后再调用resourceManager的接口获取资源。  
注:该方法不推荐使用,因为需要开发者手动维护调用名称与HSP内部的资源名称一致。
```ts
Button('getStringValue')
  .onClick(()=> {
    getContext().createModuleContext('library').resourceManager.getStringByName("shared_desc")
      .then(value => {
        console.log("getStringByName value is " + value);
      })
      .catch(error => {
        console.log("getStringByName promise error is " + error);
      });
  })
  .width("50%")
```

#### 导出HSP中资源给使用方使用
可以使用一个类来提供对外导出资源的接口,该方案的好处是:
- HSP开发者可以控制自己需要导出的资源,不需要对外暴露的资源可以不用导出
- 使用方无须感知HSP内部的资源名称
- HSP内部的资源名称变化时,不需要使用方跟着修改

具体实现如下:

封装对外提供资源的接口类:
```ts
// library/src/main/ets/ResManager.ets
export class ResManager{
  static getPic(){
    return $r("app.media.pic");
  }
}
```

`index.ts`中导出该类:
```ts
// library/src/main/ets/index.ets
export { ResManager } from './ResManager'
```

将ResManager导入使用方代码文件:
```ts
// 使用方
import {ResManager} from "library"
```

再以`ResManager.getPic()`的API获取资源,如下面的Image组件:
```ts
// 使用方
Image(ResManager.getPic())
    .width("100%")
```

J
jsjzju 已提交
144 145 146
### 导出native方法
`HSP`中也可以包含`C++`编写的`so`。对于`so`中的`native`方法,`HSP`通过间接的方式导出,以导出`libnative.so`的乘法接口`multi`为例:
```ts
J
junyi233 已提交
147
// library/src/main/ets/utils/nativeTest.ts
J
jsjzju 已提交
148 149 150 151 152 153 154 155 156 157 158 159 160 161
import native from "libnative.so"

export function nativeMulti(a: number, b: number) {
    return native.multi(a, b);
}
```

对外暴露的接口,需要在入口文件`index.ets`中声明:
```ts
// library/src/main/ets/index.ets
export { nativeMulti } from './utils/nativeTest'
```

## 使用应用内HSP
J
junyi233 已提交
162 163 164
要使用HSP中的接口,首先需要在使用方的oh-package.json5中配置对它的依赖,配置方式可[参考](https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/hsp-0000001521396322-V3#section6161154819195)
依赖配置成功后,就可以像使用HAR一样调用HSP的对外接口了。 例如,上面的library已经导出了下面这些接口:

J
jsjzju 已提交
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
```ts
// library/src/main/ets/index.ets
export { Log, add, minus } from './utils/test'
export { MyTitleBar } from './components/MyTitleBar'
export { nativeMulti } from './utils/nativeTest'
```
在使用方的代码中,可以这样使用:
```ts
// entry/src/main/ets/pages/index.ets
import { Log, add, MyTitleBar, nativeMulti } from "library"

@Entry
@Component
struct Index {
  @State message: string = 'Hello World'
  build() {
    Row() {
      Column() {
        MyTitleBar()
        Text(this.message)
          .fontSize(30)
          .fontWeight(FontWeight.Bold)
        Button('add(1, 2)')
          .onClick(()=>{
            Log.info("add button click!");
            this.message = "result: " + add(1, 2);
          })
        Button('nativeMulti(3, 4)')
          .onClick(()=>{
            Log.info("nativeMulti button click!");
            this.message = "result: " + nativeMulti(3, 4);
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}
X
xsz233 已提交
203 204
```

X
xsz233 已提交
205
### 页面路由跳转
X
xsz233 已提交
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258

若开发者想在entry模块中,添加一个按钮跳转至library模块中的menu页面(路径为:`library/src/main/ets/pages/menu.ets`),那么可以在使用方的代码(entry模块下的Index.ets,路径为:`entry/src/main/ets/MainAbility/Index.ets`)里这样使用:
```ts
import router from '@ohos.router';

@Entry
@Component
struct Index {
    @State message: string = 'Hello World'

    build() {
    Row() {
        Column() {
        Text(this.message)
            .fontSize(50)
            .fontWeight(FontWeight.Bold)
        // 添加按钮,以响应用户点击
        Button() {
            Text('click to menu')
            .fontSize(30)
            .fontWeight(FontWeight.Bold)
        }
        .type(ButtonType.Capsule)
        .margin({
            top: 20
        })
        .backgroundColor('#0D9FFB')
        .width('40%')
        .height('5%')
        // 绑定点击事件
        .onClick(() => {
            router.pushUrl({
              url: '@bundle:com.example.hmservice/library/ets/pages/menu'
            }).then(() => {
              console.log("push page success");
            }).catch(err => {
              console.error(`pushUrl failed, code is ${err.code}, message is ${err.message}`);
            })
        })
      .width('100%')
    }
    .height('100%')
    }
  }
}
```
其中`router.pushUrl`方法的入参中`url`的内容为:
```ets
'@bundle:com.example.hmservice/library/ets/pages/menu'
```
`url`内容的模板为:
```ets
'@bundle:包名(bundleName)/模块名(moduleName)/路径/页面所在的文件名(不加.ets后缀)'
J
jsjzju 已提交
259
```