文档管理中心
FAQS技术应用拉起元服务

应用拉起元服务

问题现象

应用如何拉起开发者自身或三方开发的元服务?

背景知识

  • 元服务是HarmonyOS提供的一种轻量应用程序形态,具备秒开直达,纯净清爽;服务相伴,恰合时宜;即用即走,账号相随;一体两面,嵌入运行;AI智能,全域流转;高效开发,生而可信等特征。
  • 关联主体,也称关联实体,指与开发者具有关联关系的自然人、法人或组织。开发者可以将与HarmonyOS开放平台账号主体具有关联关系的主体申请绑定为关联主体。企业开发者可创建关联主体账号组,关联主体账号组内的成员可享受该账号组内专享的跳转互通政策。

解决方案

不建议使用下面的方式打开元服务:

展开

拉起方式

原因

通过FunctionalButton拉起元服务。

FunctionalButton组件打开元服务需要获取未开放的信息,增加开发成本。

通过startAbility/startAbilityForResult拉起元服务。

使用该接口打开元服务需要获取未开放的信息,增加开发成本。

  • 方案一:使用FullScreenLaunchComponent拉起元服务。

    FullScreenLaunchComponent允许开发者以全屏方式拉起元服务,使得应用能够提供更友好的用户体验。当被拉起方授权使用方应用嵌入式运行元服务时,使用方应用可全屏嵌入式运行该服务。若未授权,则使用方应用将以跳出式方式拉起元服务。

    收起
    自动换行
    深色代码主题
    复制
    1. @Component
    2. struct ByFullScreenLaunch {
    3. @Builder
    4. PhoneRechargeChild() {
    5. Column() {
    6. Button('ByFullScreenLaunch')
    7. .fontSize(16)
    8. .width(200)
    9. };
    10. }
    11. build() {
    12. Column() {
    13. FullScreenLaunchComponent({
    14. content: this.PhoneRechargeChild,
    15. appId: '****', // 请替换为待拉起元服务的真实appId
    16. options: {},
    17. });
    18. };
    19. }
    20. }
  • 方案二:使用openAtomicService拉起元服务。

    openAtomicService打开一个独立窗口的元服务,并返回结果。使用Promise异步回调。仅支持在主线程调用。对于关联主体,首次跳转弹窗,后续直接跳转,非关联主体则每次跳转弹窗。

    收起
    自动换行
    深色代码主题
    复制
    1. @Component
    2. struct ByOpenAtomicService {
    3. build() {
    4. Column() {
    5. Button('ByOpenAtomicService')
    6. .fontSize(16)
    7. .width(200)
    8. .onClick(() => {
    9. let context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
    10. let appId: string = '****'; // 请替换为待拉起元服务的真实appId
    11. let options: AtomicServiceOptions = {
    12. flags: wantConstant.Flags.FLAG_INSTALL_ON_DEMAND
    13. };
    14. try {
    15. context.openAtomicService(appId, options)
    16. .then((result: common.AbilityResult) => {
    17. // 执行正常业务
    18. console.info(`openAtomicService succeed, resultCode: ${result.resultCode}`);
    19. })
    20. .catch((err: BusinessError) => {
    21. // 处理业务逻辑错误
    22. console.error(`openAtomicService failed, code is ${err.code}, message is ${err.message}`);
    23. });
    24. } catch (err) {
    25. // 处理入参错误异常
    26. let code = (err as BusinessError).code;
    27. let message = (err as BusinessError).message;
    28. console.error(`openAtomicService failed, code is ${code}, message is ${message}`);
    29. }
    30. });
    31. };
    32. }
    33. }
  • 方案三:使用openLink拉起元服务。

    openLink接口实现以App Linking方式拉起元服务,开发者可根据业务需求进行编译。若有匹配的元服务,则直接打开目标元服务;否则,抛异常给开发者进行处理。

    收起
    自动换行
    深色代码主题
    复制
    1. @Component
    2. struct ByOpenLink {
    3. build() {
    4. Column() {
    5. Button('ByOpenLink')
    6. .fontSize(16)
    7. .width(200)
    8. .onClick(() => {
    9. let context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
    10. // 请替换成真实元服务链接
    11. let link: string = '****';
    12. context.openLink(link)
    13. .then(() => {
    14. // 执行正常业务
    15. console.info('openAtomicService succeed');
    16. })
    17. .catch((err: BusinessError) => {
    18. // 处理业务逻辑错误
    19. console.error(`openAtomicService failed, code is ${err.code}, message is ${err.message}`);
    20. });
    21. });
    22. };
    23. }
    24. }
  • 方案四:使用FunctionalButton拉起元服务。

    FunctionalButton组件,为开发者提供场景化开发能力,支持打开元服务。对于关联主体,首次跳转弹窗,后续直接跳转,非关联主体则每次跳转弹窗。

    收起
    自动换行
    深色代码主题
    复制
    1. @Component
    2. struct ByFunctionalButton {
    3. build() {
    4. Column() {
    5. FunctionalButton({
    6. params: {
    7. openType: functionalButtonComponentManager.OpenType.LAUNCH_APP,
    8. label: 'ByFunctionalButton',
    9. appParam: {
    10. bundleName: '****', // 请替换为待拉起元服务真实bundleName
    11. abilityName: '****', // 请替换为待拉起元服务真实abilityName
    12. },
    13. styleOption: {
    14. styleConfig: new functionalButtonComponentManager.ButtonConfig()
    15. .fontSize(16)
    16. .width(200)
    17. },
    18. },
    19. controller: new functionalButtonComponentManager.FunctionalButtonController().onLaunchApp((err) => {
    20. if (err) {
    21. // 异常处理
    22. return;
    23. }
    24. })
    25. });
    26. };
    27. }
    28. }
  • 方案五:使用startAbility/startAbilityForResult拉起元服务。
    startAbility/startAbilityForResult拉起元服务。
    收起
    自动换行
    深色代码主题
    复制
    1. @Component
    2. struct ByStartAbility {
    3. build() {
    4. Column() {
    5. Button('ByStartAbility')
    6. .fontSize(16)
    7. .width(200)
    8. .onClick(() => {
    9. let context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
    10. let want: Want = {
    11. bundleName: '****', // 请替换为待拉起元服务真实bundleName
    12. abilityName: '****', // 请替换为待拉起元服务真实abilityName
    13. };
    14. try {
    15. context.startAbility(want, (err: BusinessError) => {
    16. if (err.code) {
    17. // 处理业务逻辑错误
    18. console.error(`startAbility failed, code is ${err.code}, message is ${err.message}`);
    19. return;
    20. }
    21. // 执行正常业务
    22. console.info('startAbility succeed');
    23. });
    24. } catch (err) {
    25. // 处理入参错误异常
    26. let code = (err as BusinessError).code;
    27. let message = (err as BusinessError).message;
    28. console.error(`startAbility failed, code is ${code}, message is ${message}`);
    29. }
    30. });
    31. };
    32. }
    33. }
  • 方案六:使用HalfScreenLaunchComponent组件半屏嵌入式启动元服务组件,当被拉起方未授权嵌入式运行元服务时,宿主将使用跳出式拉起元服务。
    收起
    自动换行
    深色代码主题
    复制
    1. @Component
    2. struct ByHalfScreenLaunch {
    3. build() {
    4. Column() {
    5. HalfScreenLaunchComponent({
    6. appId: '****', // 请替换为待拉起元服务的真实appId
    7. options: {},
    8. onTerminated: (info: TerminationInfo) => {
    9. console.info('onTerminated info = ' + info.want);
    10. },
    11. onError: (err) => {
    12. console.error(' onError code: ' + err.code + ', message: ', err.message);
    13. },
    14. }) {
    15. Column() {
    16. Button('ByHalfScreenLaunch')
    17. .fontSize(16)
    18. .width(200)
    19. };
    20. };
    21. };
    22. }
    23. }

完整示例参考如下:

收起
自动换行
深色代码主题
复制
  1. import { FullScreenLaunchComponent, HalfScreenLaunchComponent } from '@kit.ArkUI';
  2. import { AtomicServiceOptions, common, Want, wantConstant } from '@kit.AbilityKit';
  3. import { BusinessError } from '@kit.BasicServicesKit';
  4. import { FunctionalButton, functionalButtonComponentManager } from '@kit.ScenarioFusionKit';
  5. @Entry
  6. @Component
  7. struct AppLaunchAtomicService {
  8. build() {
  9. Navigation() {
  10. Column({ space: 40 }) {
  11. ByFullScreenLaunch();
  12. ByOpenAtomicService();
  13. ByOpenLink();
  14. ByFunctionalButton();
  15. ByStartAbility();
  16. ByHalfScreenLaunch();
  17. }
  18. .height('100%')
  19. .width('100%')
  20. .justifyContent(FlexAlign.Center);
  21. }
  22. .title('应用拉起元服务')
  23. .hideBackButton(true)
  24. .titleMode(NavigationTitleMode.Mini)
  25. .mode(NavigationMode.Stack);
  26. }
  27. }
  28. @Component
  29. struct ByFullScreenLaunch {
  30. @Builder
  31. PhoneRechargeChild() {
  32. Column() {
  33. Button('ByFullScreenLaunch')
  34. .fontSize(16)
  35. .width(200)
  36. };
  37. }
  38. build() {
  39. Column() {
  40. FullScreenLaunchComponent({
  41. content: this.PhoneRechargeChild,
  42. appId: '****', // 请替换为待拉起元服务的真实appId
  43. options: {},
  44. });
  45. };
  46. }
  47. }
  48. @Component
  49. struct ByOpenAtomicService {
  50. build() {
  51. Column() {
  52. Button('ByOpenAtomicService')
  53. .fontSize(16)
  54. .width(200)
  55. .onClick(() => {
  56. let context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
  57. let appId: string = '****'; // 请替换为待拉起元服务的真实appId
  58. let options: AtomicServiceOptions = {
  59. flags: wantConstant.Flags.FLAG_INSTALL_ON_DEMAND
  60. };
  61. try {
  62. context.openAtomicService(appId, options)
  63. .then((result: common.AbilityResult) => {
  64. // 执行正常业务
  65. console.info(`openAtomicService succeed, resultCode: ${result.resultCode}`);
  66. })
  67. .catch((err: BusinessError) => {
  68. // 处理业务逻辑错误
  69. console.error(`openAtomicService failed, code is ${err.code}, message is ${err.message}`);
  70. });
  71. } catch (err) {
  72. // 处理入参错误异常
  73. let code = (err as BusinessError).code;
  74. let message = (err as BusinessError).message;
  75. console.error(`openAtomicService failed, code is ${code}, message is ${message}`);
  76. }
  77. });
  78. };
  79. }
  80. }
  81. @Component
  82. struct ByOpenLink {
  83. build() {
  84. Column() {
  85. Button('ByOpenLink')
  86. .fontSize(16)
  87. .width(200)
  88. .onClick(() => {
  89. let context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
  90. // 请替换成真实元服务链接
  91. let link: string = '****';
  92. context.openLink(link)
  93. .then(() => {
  94. // 执行正常业务
  95. console.info('openAtomicService succeed');
  96. })
  97. .catch((err: BusinessError) => {
  98. // 处理业务逻辑错误
  99. console.error(`openAtomicService failed, code is ${err.code}, message is ${err.message}`);
  100. });
  101. });
  102. };
  103. }
  104. }
  105. @Component
  106. struct ByFunctionalButton {
  107. build() {
  108. Column() {
  109. FunctionalButton({
  110. params: {
  111. openType: functionalButtonComponentManager.OpenType.LAUNCH_APP,
  112. label: 'ByFunctionalButton',
  113. appParam: {
  114. bundleName: '****', // 请替换为待拉起元服务真实bundleName
  115. abilityName: '****', // 请替换为待拉起元服务真实abilityName
  116. },
  117. styleOption: {
  118. styleConfig: new functionalButtonComponentManager.ButtonConfig()
  119. .fontSize(16)
  120. .width(200)
  121. },
  122. },
  123. controller: new functionalButtonComponentManager.FunctionalButtonController().onLaunchApp((err) => {
  124. if (err) {
  125. // 异常处理
  126. return;
  127. }
  128. })
  129. });
  130. };
  131. }
  132. }
  133. @Component
  134. struct ByStartAbility {
  135. build() {
  136. Column() {
  137. Button('ByStartAbility')
  138. .fontSize(16)
  139. .width(200)
  140. .onClick(() => {
  141. let context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
  142. let want: Want = {
  143. bundleName: '****', // 请替换为待拉起元服务真实bundleName
  144. abilityName: '****', // 请替换为待拉起元服务真实abilityName
  145. };
  146. try {
  147. context.startAbility(want, (err: BusinessError) => {
  148. if (err.code) {
  149. // 处理业务逻辑错误
  150. console.error(`startAbility failed, code is ${err.code}, message is ${err.message}`);
  151. return;
  152. }
  153. // 执行正常业务
  154. console.info('startAbility succeed');
  155. });
  156. } catch (err) {
  157. // 处理入参错误异常
  158. let code = (err as BusinessError).code;
  159. let message = (err as BusinessError).message;
  160. console.error(`startAbility failed, code is ${code}, message is ${message}`);
  161. }
  162. });
  163. };
  164. }
  165. }
  166. @Component
  167. struct ByHalfScreenLaunch {
  168. build() {
  169. Column() {
  170. HalfScreenLaunchComponent({
  171. appId: '****', // 请替换为待拉起元服务的真实appId
  172. options: {},
  173. onTerminated: (info: TerminationInfo) => {
  174. console.info('onTerminated info = ' + info.want);
  175. },
  176. onError: (err) => {
  177. console.error(' onError code: ' + err.code + ', message: ', err.message);
  178. },
  179. }) {
  180. Column() {
  181. Button('ByHalfScreenLaunch')
  182. .fontSize(16)
  183. .width(200)
  184. };
  185. };
  186. };
  187. }
  188. }

常见FAQ

Q:全屏嵌入式和跳出式运行元服务区别是什么?

A:全屏嵌入式运行元服务是指,通过UIExtensionComponent的组件方式嵌入到使用方的组件树中,拉起EmbeddableUIAbility,展示提供方的应用内容。能够实现组件式的交互体验。跳出式运行元服务是指,非组件化的方式拉起EmbeddableUIAbility,交互体验接近独立窗口。

Q:元服务是否支持跳转应用?

A:如果被拉起方是非关联主体的三方应用,则无法拉起。如果被拉起方是关联主体账号组的三方应用,则可以拉起。详情请参考跳转规则说明

在 FAQ 中进行搜索
请输入您想要搜索的关键词