在鸿蒙应用开发中,有时候我们会创建HAR 模块封装一些SDK能力提供给第三方APP进行集成。
鸿蒙的har 包并不支持定义page页面对外导出,也不支持配置路由信息,因此我们多是在har包中提供组件,通过导出组件的形式,提供给App引用使用。
在鸿蒙中,非@Entry装饰的组件,只能收到如下生命周期函数的回调
对于页面级组件来说,就可以收到
但是在实际使用过程中,如果我们的har包中想提供跟页面组件一样的功能,受限于har限制,不能定义为@Entry 组件,因而无法接收到上述三个函数的回调,实际功能会收到限制。那有没有办法解决上述问题呢?
我们在har模块中定义一个子组件,pages/SdkPage.ets
@Component
export struct SdkPage {
build() {
...
}
}
在App中定义壳页面,pages/SdkPageShell.ets
这里也可以创建一个HSP对外提供,壳页面配置在HSP包中,对外提供HSP给App集成(这个HSP的,后面有时间在单独写一篇进行讲解SDK的封装,有兴趣的可以私信我或者评论区留言)。
@Entry
@Component
export struct SdkPageShell {
build() {
Column() {
SdkPage()
}.width('100%')
.height('100%')
}
}
套娃模式,这样我们就能将har包中的子组件作为页面级别进行展示了。App需要对SdkPageShell进行页面路由配置。
SdkPageShell 作为一个空壳页面。
但是在实际开发中,就会出现正文前言提到的问题,有部分生命周期函数无法收到回调, 导致我们开发页面功能时处处受限,比如页面隐藏时进行一些消息取消订阅,页面显示时进行消息订阅,如果是要做编辑功能,希望是用户在触发手机实体键的时候,弹窗询问用户是否进行数据保存,不能收到
onBackPress回调,那功能就无法实现了。
那应该怎么做呢,接着往下看。
经过对子组件的个追踪,发现 在子组件中,是能够获取到父组件的实例的parent_,那我们就可以对其进行一点点的处理。如果我们的子组件是页面组件下的一级子组件,那this[‘parent_’] 拿到的就是上文提到的壳页面SdkPageShell ,
parent_无法直接获取到,我们通过this[‘parent_’] 就可以拿到实例。
那这里有一个思路,我们对this[‘parent_’] 进行一个生命周期函数的方法注入。
在SdkPage.ets中,
aboutToAppear() {
this['parent_'].onBackPress= this.onBackPress.bind(this);
};
onBackPress() {
Logger.info(this.TAG, 'onBackPress is called');
return true;
}
既然按实体返回键的时候,系统会回调壳页面的onBackPress函数,在壳页面中重写onBackPress就可以收到回调, 那我们这里给壳页面注入一个onBackPress进行替换,然后绑定到SdkPage子组件上的onBackPress中去,这样是不是就可以收到回调呢?按这个思路好像是行得通,那就运行试试看,可是很遗憾不能生效。原因是我们改动的是运行期壳页面的onBackPress方法,系统触发实际调用的是CustomComponent的onBackPress。
那壳页面重写onBackPress是能够收到回调,那在壳页面进行一点修改不就可以了,
在SdkPageShell.ets中,
@Entry
@Component
export struct SdkPageShell {
build() {
Column() {
SdkPage()
}.width('100%')
.height('100%')
}
onBackPress() {
if (this['onBackPressHook']) {
return this['onBackPressHook'].call(this);
}
}
}
看到这里,会不会有点懵,onBackPressHook是啥,SdkPageShell中并未定义onBackPressHook,这里的代码能生效吗,相信有的同学已经反应过来,没错,我们要到子组件中对SdkPageShell进行 onBackPressHook方法的注入。
这里贴下完整代码:
在SdkPage.ets中,
@Component
export struct SdkPage {
build() {
...
}
aboutToAppear() {
this.addEvent();
};
aboutToDisappear() {
}
addEvent() {
this['parent_'].onBackPressHook= this.onBackPress.bind(this);
}
onBackPress() {
Logger.info(this.TAG, 'onBackPress is called');
this.handlePageBack();
return true;
}
}
这样,在按了手机的物理返回键的时候,子组件SdkPage 就能在onBackPress中收到回调,在handlePageBack中进行返回事件处理,比如弹窗提供用户进行数据保存, return true意思是要拦截系统返回,这样页面就不会被关闭。
其他的生命周期函数,处理方式跟上述的方式一致,总结思路如下:
上述方法,只需要App配合,写少量代码,在壳页面中进行生命周期函数的调用,或者是SDK提供方提供壳页面给到App。如果觉得这样还是不够简洁,那就得考虑提供HSP包给App集成,而不是提供HAR包,这样就可以直接提供Page而不是提供组件。 上面方案也只是一个实现的思路之一,也是有其局限性,比如多个子组件的情况下,就会存在多注入覆盖的问题,因此需要根据实际开发情况来选择实现方案,本文这里仅提供一种实现思路,如果有其他实现方式,欢迎评论区探讨。谢谢阅读!