鸿蒙开发笔记-16-应用间跳转

以下内容均基于HarmonyOS NEXT版本

为什么需要应用间跳转

1.用户场景驱动
  • 社交分享:图库App跳转微信发送图片
  • 服务闭环:电商App跳转地图导航至收货地址
  • 生态协同:浏览器中点击链接唤起银行App支付
2.系统级优势
  • 沙箱隔离突破:安全可控的数据传递(基于URI权限管控)
  • 垂类能力复用:避免重复开发(如直接调用高德地图导航)
  • 多设备协同:手机与车机间的跨设备跳转(扩展FA模型能力)

跳转类型

指定应用跳转(精准拉起)

  • 指定应用链接(推荐):通过openLink或startAbility接口来指定应用链接,拉起目标应用页面。
  • 指定Ability(不推荐):通过startAbility接口指定具体的Ability(即显式Want方式),拉起目标应用页面。
  • 方式:Deep Linking(自定义Scheme)或 App Linking(HTTPS+域名校验)
    • Deep Linking:是一种通过链接跳转至应用特定页面的技术,其特点是支持开发者定义任意形式的scheme。由于缺乏域名校验机制,容易被其他应用所仿冒。
    • App Linking:其限定了scheme必须为https,同时通过增加域名校验机制,可以从已匹配到的应用中筛选过滤出目标应用,消除应用查询和定位中产生的歧义,直达受信的目标应用。
  • 场景:社交分享(跳转指定购物App)、广告引流(跳转推广页面)
使用canOpenLink判断应用是否可访问
extendtypescript 复制代码
import { bundleManager } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
try {
  let link = 'app1Scheme://test.example.com/home';
  let canOpen = bundleManager.canOpenLink(link);
  hilog.info(0x0000, 'testTag', 'canOpenLink successfully: %{public}s', JSON.stringify(canOpen));
} catch (err) {
  let message = (err as BusinessError).message;
  hilog.error(0x0000, 'testTag', 'canOpenLink failed: %{public}s', message);
}

指定类型跳转(垂类面板)

  • 方式:startAbilityByType() + 垂类标识(如navigation/mail)
  • 场景:导航路线规划、邮件编辑、图片处理(用户选择同类应用)

实现方案

案例1:App Linking(推荐)
  • 优势:防劫持、支持网页跳转、系统自动处理未安装场景(跳转浏览器)
  • 域名归属验证:需在AppGallery Connect后台配置数字资产链接
  • 数据防篡改:URL参数自动签名(SDK支持)
  • 创建流程
extendtypescript 复制代码
// 目标方配置(module.json5)  
"uris": [{  
  "scheme": "https",  
  "host": "www.example.com",
  "pathStartWith": "transfer" // 路径前缀匹配
  "domainVerify": true  // 开启域名认证  
}]  


// 拉起方代码  
import { common } from '@kit.AbilityKit';
try {
  await context.openLink("https://pay.demo.com/transfer?amt=100", {
    appLinkingOnly: true,  // 强制校验域名,表示是否必须以App Linking的方式启动UIAbility,默认为false。
    parameters: { token: "xxx" } // 传递参数,敏感数据建议加密
  });
} catch (error) {
  // 处理未安装场景:引导下载或网页版
}
案例2:Deep Linking(兼容旧版)
  • 限制:需处理多应用冲突弹窗;非HTTPS链接无法直接网页访问
extendtypescript 复制代码
// 目标方配置(module.json5)  
"uris": [{  
  "scheme": "myapp",  // 自定义协议  
  "host": "page"  
}]  

// 拉起方代码  
// 处理多应用冲突
const want: Want = {
  uri: "demo://product/detail?id=123",
  // 增加entity过滤避免误匹配
  entities: ["entity.system.browsable"]
};
context.startAbility(want).catch(() => {
  // 弹窗提示用户"未找到处理程序"
});
案例3:垂类面板跳转(通用意图)
  • 支持垂类:导航(RoutePlan/Navigation)、邮件(ComposeMail)、金融(Transfer)、图片编辑(PhotoEditor)
extendtypescript 复制代码
// 场景1:导航路线规划
context.startAbilityByType("navigation", {
  sceneType: 1, // 路线规划
  destination: {
    name: "北京首都机场",
    lat: 39.989,
    lon: 116.481
  }
});

// 场景2:图片编辑
context.startAbilityByType("photoEditor", {
  sourceUri: "internal://cache/photo.jpg",
  editOptions: { cropRatio: "16:9" } // 扩展参数
});

//场景3 拉起邮件类应用(mailto方式)
let ctx = getContext(this) as common.UIAbilityContext;
ctx.startAbility({
  action: 'ohos.want.action.sendToData',
  uri: 'mailto:feedback@example.com?subject=App Feedback&body=Please describe your feedback here...'
})
        
//场景4:拉起文件处理类应用(startAbility)
// 获取文件沙箱路径
let filePath = this.context.filesDir + '/test.txt';
// 将沙箱路径转换为uri
let uri = fileUri.getUriFromPath(filePath);
// 构造请求数据
let want: Want = {
  action: 'ohos.want.action.viewData', // 表示查看数据的操作,文件打开场景固定为此值
  uri: uri,
  type: 'general.plain-text', // 表示待打开文件的类型
  // 配置被分享文件的读写权限,例如对文件打开应用进行读写授权
  flags: wantConstant.Flags.FLAG_AUTH_WRITE_URI_PERMISSION | wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION
};
// 调用接口启动
this.context.startAbility(want)
  .then(() => {
    console.info('Succeed to invoke startAbility.');
  })
  .catch((err: BusinessError) => {
    console.error(`Failed to invoke startAbility, code: ${err.code}, message: ${err.message}`);
  });        
        
        
        
//开发者可注册新的垂类类型(需向华为申请审核),例如:
// 新建ExtAbility
"type": "custom_editor",
"metadata": [{
  "name": "custom_editor",
  "value": "VideoEditor" // 新垂类标识
}]
案例4. 隐式Want跳转(通用兜底)
extendtypescript 复制代码
const want: Want = {
  // 不指定具体组件
  action: "ohos.want.action.EDIT_DATA",
  uri: "file://docs/report.docx", // 根据文件类型匹配
  type: "application/vnd.ms-word" // MIME类型辅助匹配
};
案例5. 使用Web组件实现应用跳转
  • Web组件需要跳转DeepLink链接应用时,可通过拦截回调onLoadIntercept中对定义的事件进行处理,实现应用跳转。
extendtypescript 复制代码
// index.ets
import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
@Entry
@Component
struct WebComponent {
  controller: webview.WebviewController = new webview.WebviewController();
  build() {
    Column() {
      Web({ src: $rawfile('index.html'), controller: this.controller })
        .onLoadIntercept((event) => {
          const url: string = event.data.getRequestUrl();
          if (url === 'link://www.example.com') {
            (getContext() as common.UIAbilityContext).openLink(url)
              .then(() => {
                console.log('openLink success');
              }).catch((err: BusinessError) => {
                console.error('openLink failed, err:' + JSON.stringify(err));
              });
            return true;
          }
          // 返回true表示阻止此次加载,否则允许此次加载
          return false;
        })
    }
  }
}

我是今阳,如果想要进阶和了解更多的干货,欢迎关注微信公众号 "今阳说" 接收我的最新文章

相关推荐
shayu8nian16 分钟前
鸿蒙的NDK开发初级入门篇
华为·harmonyos
0wioiw017 分钟前
Flutter基础(前端教程⑧-数据模型)
前端·flutter·状态模式
一笑code27 分钟前
UC浏览器PC版自2016年后未再更新不支持vue3
前端·vue
好记性不如1 小时前
在前端项目中是如何解决跨域的
前端
东风西巷5 小时前
NealFun安卓版:创意无限,娱乐至上
android·人工智能·智能手机·娱乐·软件需求
前端 贾公子7 小时前
pnpm 的 resolution-mode 配置 ( pnpm 的版本解析)
前端
伍哥的传说8 小时前
React 自定义Hook——页面或元素滚动到底部监听 Hook
前端·react.js·前端框架
麦兜*10 小时前
Spring Boot 集成Reactive Web 性能优化全栈技术方案,包含底层原理、压测方法论、参数调优
java·前端·spring boot·spring·spring cloud·性能优化·maven
知了一笑10 小时前
独立开发第二周:构建、执行、规划
java·前端·后端