基于原生能力的跨应用跳转

基于原生能力的跨应用跳转

HarmonyOS
2024-06-11 19:53:29
1254浏览
收藏 0
回答 1
回答 1
按赞同
/
按时间
davis_li

使用原生能力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", 
  ], 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

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

"abilities": [ 
{ 
  "skills": [ 
  { 
    "entities": [ 
    "entity.system.home" 
    ], 
    "actions": [ 
    "action.system.home" 
    ], 
    "uris": [ 
    { 
      "scheme": 'payapp' 
    } 
    ], 
  } 
  ] 
} 
]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

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) 
  } 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.

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.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 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.

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

显示效果:

核心代码

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

"module": { 
  ... 
  "querySchemes": [ 
  "bank1", 
  ... 
  "bank9" 
  ] 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

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'), 
]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

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

Button("跳转支付列表") 
  .onClick(() => { 
    if (this.dialogController != null) { 
      this.dialogController.open() 
    } 
  })
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

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

@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 
  }), 
})
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.

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

//每行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()) 
      } 
    } 
  } 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
分享
微博
QQ
微信
回复
2024-06-12 16:16:45
相关问题
基于原生水印添加能力
1706浏览 • 1回复 待解决
基于原生能力组件封装
1347浏览 • 1回复 待解决
基于原生模块资源访问
1630浏览 • 1回复 待解决
基于原生能力网络状态感知
1443浏览 • 1回复 待解决
基于原生能力网络加载性能分析
1899浏览 • 1回复 待解决
基于原生能力设备唯一ID方案
1584浏览 • 1回复 待解决
基于原生能力实现图文混排
1464浏览 • 1回复 待解决
基于原生应用主题开发
1379浏览 • 1回复 待解决
基于TLSSocket通信能力
1468浏览 • 1回复 待解决
如何实现设备内应用UIAbility跳转
3276浏览 • 1回复 待解决
基于原生实现高级显示效果
1454浏览 • 1回复 待解决
基于@ohos/axios网络请求能力
1388浏览 • 1回复 待解决
HarmonyOS原生分享能力使用
1712浏览 • 1回复 待解决
基于ArkUI实现类似.9图拉伸能力
1489浏览 • 1回复 待解决
基于HAR模块C++头文件引用
1904浏览 • 1回复 待解决
HarmonyOS 系统原生能力是否支持PDF预览
1572浏览 • 1回复 待解决
如何使用原生能力人脸识别api?
917浏览 • 1回复 待解决
HarmonyOS 模块页面跳转
859浏览 • 1回复 待解决
HarmonyOS 模块无法跳转
920浏览 • 1回复 待解决