【鸿蒙实战开发】基于原生能力的跨应用跳转

101 篇文章 1 订阅
101 篇文章 0 订阅

场景描述

使用原生能力startability启动其他应用前,开发者需要判断目标应用是否安装,从而执行不同的逻辑,例如:

场景一:支付时商户根据实际情况去判断,拉起支付应用还是h5页面。

场景二:分享场景与支付场景,需要列出多个用户可跳转的应用。

业务诉求:

场景一:支付时商户根据实际情况去判断,拉起支付应用还是h5页面

显示效果:

1.支付应用存在,拉起支付应用。

2.支付应用不存在,拉起h5页面进行支付。

核心代码

1.在拉起方的module.json5文件中配置querySchemes字段,表示本应用可能会用到的scheme查询,比如这里配置的payapp代表本应用可以使用bundleManager.canOpenLink(),来查询scheme为payapp的链接是否可以打开(payapp://xx?xx=1&yy=2)

"module": {

  "querySchemes": [

  "payapp",

  ],

}

2.在被拉起方的module.json文件中的skill字段中配置该应用支持的scheme协议,表示这个应用可以通过此协议打开。

"abilities": [

{

  "skills": [

  {

    "entities": [

    "entity.system.home"

    ],

    "actions": [

    "action.system.home"

    ],

    "uris": [

    {

      "scheme": 'payapp'

    }

    ],

  }

  ]

}

]

3.在拉起方中通过bundleManager.canOpenLink()判断该链接能否打开,可以打开的话跳转支付应用进行支付,不能打开的话跳转h5页面来下载应用或者支付。

// payapp:// 后的字段可以自定义,需要由被拉起方应用进行处理

let paylink = 'payapp://startpay?apppid=123456&page=xxx/pay&query=10';

let paydata = bundleManager.canOpenLink(paylink);

if (paydata) {

  let want: Want = {

    uri: paylink

  };

  let context = getContext(this) as common.UIAbilityContext;

  context.startAbility(want, (error: BusinessError) => {

    console.error(`error.code = ${error.code}`);

  });

} else {

  this.pageInfos.pushPath({ name: 'PayWeb' })

}

//PayWeb

import web_webview from '@ohos.web.webview';

import business_error from '@ohos.base';

@Component

export struct PayWebInfo {

  @Consume('pageInfos') pageInfos: NavPathStack;

  webviewController: web_webview.WebviewController = new web_webview.WebviewController();

  aboutToAppear() {

    try {

      this.webviewController.loadUrl($rawfile("pay.html"));

    } catch (error) {

      let e: business_error.BusinessError = error as business_error.BusinessError;

      console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);

    }

  }

  build() {

    NavDestination() {

      Column() {

        Web({ src: $rawfile("pay.html"), controller: this.webviewController })

      }.width('100%').height('100%')

    }.hideTitleBar(true)

  }

}

4.被调用方在冷启动热启动的情况下都要拉起同一个支付页面,就需要在onNewWant,onCreate,onWindowStageCreate中都添加跳转支付页面的相关逻辑。

//定义一个接口接收want传入的数据

interface StartParm {

  bundleName?: string

  uriResult: uri.URI

  started: boolean

}

//将want数据存入

function parseStartWant(want: Want): StartParm | undefined {

  if (want.uri) {

    let startParam: StartParm = {

      bundleName: want.bundleName,

      uriResult: new uri.URI(want.uri),

      started: false

    }

    return startParam

  } else {

    return undefined

  }

}

​

export default class EntryAbility extends UIAbility {

  startParam?: StartParm

  ​

  // 冷热启动均执行,用于跳转支付页面

  action() {

    if (this.startParam && !this.startParam.started) {

      this.startParam.started = true

      let pageInfos = AppStorage.get<NavPathStack>("pageInfos") as NavPathStack;

      //判断支付页面是否存在

      let data =pageInfos.getIndexByName('PayPage')

      if ( data.length == 0 ) {

        pageInfos.pushPath({ name: 'PayPage' })

      }else  {

        pageInfos.removeByName('PayPage')

        pageInfos.pushPath({ name: 'PayPage' })

      }

    }

  }

  ​

  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {

    this.startParam = parseStartWant(want)

    //本Demo通过AppStorage将传入的数据展示在页面上,例如消费应用,消费金额等

    AppStorage.setOrCreate<StartParm>("Param",this.startParam );

  }

  ​

  onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {

    this.startParam = parseStartWant(want)

    //数据处理同onCreate

    AppStorage.setOrCreate<StartParm>("Param",this.startParam );

    //跳转支付页面

    this.action()

  }

  onWindowStageCreate(windowStage: window.WindowStage): void {

    windowStage.loadContent('pages/Index', (err) => {

      if (err.code) {

        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');

        return;

      }

      //由于时序问题,需要使用setTimeout保证页面压栈的顺序

      setTimeout(()=>{

        //跳转支付页面

        this.action()

      })

    });

  }

}

场景二:分享场景与支付场景,需要列出多个用户可跳转的应用。

显示效果:

核心代码

1.同场景一Step1,需要在querySchemes中配置需要进行跳转检测的应用。

"module": {

  ...

  "querySchemes": [

  "bank1",

  ...

  "bank9"

  ]

}

2.在拉起方中遍历想要跳转的所有应用,并在弹窗中显示可以被拉起的应用。

准备被拉起方的app信息,其中目标app的图标需要拉起方应用自己准备。uri字段规格详见文末的常见问题Q1。

private payApps: PayApp[] = [

  new PayApp('银行1', $r("app.media.startIcon"), 'bank1://xx?xx'),

  ...

  new PayApp('银行9', $r("app.media.startIcon"), 'bank9://xx?xx'),

]

添加按钮,点击出现支付应用列。

Button("跳转支付列表")

  .onClick(() => {

    if (this.dialogController != null) {

      this.dialogController.open()

    }

  })

添加自定义弹窗,定义弹窗以及弹窗中分割线的属性:

@State egDivider: DividerTmp = new DividerTmp(1, 10, 10, '# ffe9f0f0')

​

//增加一个类方便定义分割线属性

class DividerTmp {

  strokeWidth: Length = 1           //分割线宽度

  startMargin: Length = 10          //分割线距离左端长度

  endMargin: Length = 10            //分割线距离右端长度

  color: ResourceColor = '# ffe9f0f0'//分割线颜色

  ​

  constructor(strokeWidth: Length, startMargin: Length, endMargin: Length, color: ResourceColor) {

    this.strokeWidth = strokeWidth

    this.startMargin = startMargin

    this.endMargin = endMargin

    this.color = color

  }

}

​

//自定义弹窗

dialogController: CustomDialogController | null = new CustomDialogController({

  builder: CustomDialogExample({

    payApps: this.payApps,

    egDivider: this.egDivider

  }),

})

在弹窗显示之前判断应用是否已安装,在弹窗中显示已安装的应用,并实现点击跳转到该应用。

//每行app的信息

class PayApp {

  name: string;

  icon: Resource;

  link: string;

  installed: boolean = false

  ...

}

​

@CustomDialog

struct CustomDialogExample {

  @Prop payApps: PayApp[]

  @Prop egDivider: DividerTmp

  controller?: CustomDialogController

  aboutToAppear(): void {

    for (let item of this.payApps) {

      item.installed = bundleManager.canOpenLink(item.link)

    }

    this.payApps = this.payApps.filter((app) => app.installed)

  }

  ​

  build() {

    Column() {

      ...

      List() {

        ForEach(this.payApps, (item: PayApp) => {

          ListItem() {

            Row() {

              Image(item.icon).width(25).height(25).margin(10)

              Text(item.name).fontSize(20)

            }

            .onClick(() => {

              let context = getContext() as common.UIAbilityContext

              context.startAbility({ uri: item.link })

            })

            .justifyContent(FlexAlign.Start)

          }

        }, (item: PayApp) => item.name.toString())

      }

    }

  }

}

鸿蒙全栈开发全新学习指南

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以要有一份实用的鸿蒙(HarmonyOS NEXT)学习路线与学习文档用来跟着学习是非常有必要的。

针对一些列因素,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的核心知识要点,内容有(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、WebGL、元服务、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植等等)鸿蒙(HarmonyOS NEXT)技术知识点。

本路线共分为四个阶段

第一阶段:鸿蒙初中级开发必备技能

在这里插入图片描述

第二阶段:鸿蒙南北双向高工技能基础:gitee.com/MNxiaona/733GH

第三阶段:应用开发中高级就业技术

第四阶段:全网首发-工业级南向设备开发就业技术:gitee.com/MNxiaona/733GH

《鸿蒙 (Harmony OS)开发学习手册》(共计892页)

如何快速入门?

1.基本概念
2.构建第一个ArkTS应用
3.……

开发基础知识:gitee.com/MNxiaona/733GH

1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS语言
9.……

基于ArkTS 开发

1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……

鸿蒙开发面试真题(含参考答案):gitee.com/MNxiaona/733GH

鸿蒙入门教学视频:

美团APP实战开发教学:gitee.com/MNxiaona/733GH

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:gitee.com/MNxiaona/733GH

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值