概览:本文介绍了应用间跳转的基本概念和应用场景,涵盖拉起指定应用和指定类型应用两种方式。通过App Linking和Deep Linking实现前者,通过startAbilityByType或mailto实现后者,支持导航、邮件、金融、航班等系统级应用的调用,灵活实现跨应用交互与系统功能集成。
什么是应用间跳转?
应用跳转是指从一个应用跳转至另外一个应用,传递相应的数据、执行特定的功能。通过应用跳转可以满足用户更为真实丰富的场景诉求、提升交互体验的便捷性和流畅性。
应用跳转类型
1、拉起指定应用(目标明确)
拉起方应用明确指定跳转的目标应用,来实现应用跳转。指向性跳转可以分为指定应用链接、指定Ability两种方式。
指定应用链接(推荐):使用 openLink 或 startAbility 接口,通过链接跳转至目标页面。
指定Ability(不推荐):显式Want,从 API 12 开始不再推荐使用。
2、拉起指定类型的应用(用户选择)
指定应用类型(如“地图类”)系统展示匹配应用列表,用户自主选择打开。
3、拉起系统应用
1、拉起指定应用(目标明确)
应用链接两种类型对比:
| 类型 | App Linking(推荐) | Deep Linking |
|---|---|---|
| 实现方案 | 目标应用需要在 module.json5 中声明应用链接;同时需要向系统注册域名并通过域名认证。 | 目标应用需要在 module.json5 中声明应用链接。 |
| 链接格式 | scheme 必须为 https。例如:www.example.com/product/123 | scheme 可以自定义。通常不为 https、http、file,否则会拉起默认的系统浏览器。 例如:myapp://product/123 |
| 是否可用于分享或直接在网页中访问 | 可以 | 不可以,需在代码中调用。 |
| 是否可以直接拉起目标应用 | 可以 | 可以,但不推荐使用,存在被仿冒风险。 |
两种应用链接跳转结果对比:
| 应用链接类型 | App Linking(推荐) | Deep Linking |
|---|---|---|
| appLinkingOnly 为 false | 目标应用已安装 → 直接跳转打开目标应用。 未安装 → 跳转默认浏览器打开网页。 | 目标应用已安装 → 跳转目标应用(如果有多个符合条件的应用时,展示应用选择弹框) 目标应用未安装 → 返回失败,系统不跳转,由应用自行处理;当前会展示 “链接无法打开” 弹框。 |
| appLinkingOnly 为 true | 目标应用已安装 → 直接跳转打开目标应用。 未安装 → 返回失败,系统不跳转由应用自行处理。 | 目标应用已安装 → 返回失败,系统不跳转,由应用自行处理。 目标应用未安装 → 返回失败,系统不跳转,由应用自行处理。 |
appLinkingOnly:表示是否必须以AppLinking的方式启动UIAbility。
使用App Linking实现应用间跳转
使用App Linking进行跳转时,系统会根据接口传入的uri信息(HTTPS链接)将用户引导至目标应用中的特定内容,无论应用是否已安装,用户都可以访问到链接对应的内容,跳转体验相比Deep Linking方式更加顺畅。
实现原理:
1、App Linking在Deep Linking基础上增加了域名校验环节,通过域名校验,可帮助用户消除歧义,识别合法归属于域名的应用,使链接更加安全可靠。
2、App Linking要求对于同一HTTPS网址,有应用和网页两种内容的呈现方式。当应用安装时则优先打开应用去呈现内容;当应用未安装时,则打开浏览器呈现Web版的内容。
拉起方应用跳转实现:
1、通过openLink接口拉起 拉起方应用通过UIAbilityContext.openLink()接口,拉起目标应用,配置appLinkingOnly。目标应用安装后,需要在AGC开通App Linking服务,具体开通步骤参考官方文档。 developer.huawei.com/consumer/cn…
2、通过系统浏览器或ArkWeb拉起: 当用户在系统浏览器或者集成ArkWeb的应用的网页上点击某个链接时,若有链接匹配的应用,系统则会 通过App Linking能力优先拉起目标应用,并在应用内展示相应的内容。
使用Deep Linking实现应用间跳转
Deep Linking基于隐式Want匹配机制中的uri匹配来查询、拉起目标应用。主要有以下两种拉起方式:
1、通过openLink接口拉起: 在openLink接口的link字段中传入目标应用的URL信息,options字段中的appLinkingOnly配置为false。
2、通过startAbility接口拉起: startAbility接口是将应用链接放入want中,通过调用隐式want匹配的方法触发应用跳转。
2、拉起指定类型的应用(用户选择)
拉起指定类型应用是指通过指定应用类型、而非某个具体的应用,来实现应用跳转。通常有以下几种方式:
1、通过startAbilityByType接口拉起垂类面板:调用startAbilityByType接口拉起对应的垂域面板(目前支持拉起导航、金融、邮件、航班、快递类应用面板),该面板将展示目标方接入的垂域应用,由用户选择打开指定应用以实现相应的垂类意图。
2、通过mailto方式跳转电子邮件应用:通过mailto电子邮件协议,可以创建指向电子邮件地址的超链接,方便用户通过网页或应用中的超链接直接跳转电子邮件应用。
3、通过startAbility接口打开文件:开发者可以通过调用startAbility接口,由系统从已安装的应用中寻找符合要求的应用,打开特定类型的文件。
调用方接口传入的type与wantParams.sceneType取值,与目标方在module.json5配置文件中声明的对应linkFeature应用映射关系如下:
| 支持的功能 | 调用方(startAbilityByType 接口入参) | 目标方(配置文件 linkFeature 取值) |
|---|---|---|
| 路线规划功能 | - type: navigation- wantParams.sceneType: 1 | RoutePlan |
| 导航功能 | - type: navigation- wantParams.sceneType: 2 | Navigation |
| 位置搜索功能 | - type: navigation- wantParams.sceneType: 3 | PlaceSearch |
| 转账汇款功能 | - type: finance- wantParams.sceneType: 1 | Transfer |
| 信用卡还款功能 | - type: finance- wantParams.sceneType: 2 | CreditCardRepayment |
| 撰写邮件功能 | - type: mail- wantParams.sceneType: 1 | ComposeMail |
| 按航班号查询航班功能 | - type: flight- wantParams.sceneType: 1 | QueryByFlightNo |
| 按起降地查询航班功能 | - type: flight- wantParams.sceneType: 2 | QueryByLocation |
| 快递查询功能 | - type: express- wantParams.sceneType: 1 | QueryExpress |
拉起导航类应用(startAbilityByType)
developer.huawei.com/consumer/cn…
接口type字段为navigation,支持路线规划、导航、位置搜索三种意图场景,以导航场景为例介绍 wantParam参数如下:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| sceneType | number | 是 | 意图场景,表明本次请求对应的操作意图。导航场景填2。 |
| destinationName | string | 否 | 终点名称。 |
| destinationLatitude | number | 是 | 终点纬度。 |
| destinationLongitude | number | 是 | 终点经度。 |
| destinationPoiIds | Record<number, string> | 否 | 终点POI ID列表,当前仅支持传入花瓣地图、高德地图、百度地图的POI ID。 |
拉起方开发步骤:导入相关模块。构造接口参数并调用startAbilityByType接口。终点POI ID列表(destinationPoiIds)和起点POI ID列表(originPoiIds)需开发者自行从各地图系统中获取,并按照对应关系传参。
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let wantParam: Record<string, Object> = {
'sceneType': 1,
'destinationLatitude': 32.060844,
'destinationLongitude': 118.78315,
'destinationName': 'xx市xx路xx号',
'destinationPoiIds': {
1: '1001', // key为1代表花瓣地图,value需为花瓣地图POI
2: '2002', // key为2代表高德地图,value需为高德地图POI
3: '3003' // key为3代表百度地图,value需为百度地图POI
} as Record<number, string>,
'originName': 'xx市xx公园',
'originLatitude': 31.060844,
'originLongitude': 120.78315,
'originPoiIds': {
1: '1101', // key为1代表花瓣地图,value需为花瓣地图POI
2: '2202', // key为2代表高德地图,value需为高德地图POI
3: '3303' // key为3代表百度地图,value需为百度地图POI
} as Record<number, string>,
'vehicleType': 0
};
let abilityStartCallback: common.AbilityStartCallback = {
onError: (code: number, name: string, message: string) => {
console.error(`onError code ${code} name: ${name} message: ${message}`);
},
onResult: (result) => {
console.info(`onResult result: ${JSON.stringify(result)}`);
}
}
context.startAbilityByType("navigation", wantParam, abilityStartCallback,
(err) => {
if (err) {
console.error(`startAbilityByType fail, err: ${JSON.stringify(err)}`);
} else {
console.info(`success`);
}
});
拉起邮件类应用(startAbilityByType)
developer.huawei.com/consumer/cn…
接口中type字段为mail,对应的wantParam参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| string[ ] | 否 | 收件人邮箱地址(支持多个且以逗号分隔)。 | |
| cc | string[ ] | 否 | 抄送人邮箱地址(支持多个且以逗号分隔)。 |
| bcc | string[ ] | 否 | 密送人邮箱地址(支持多个且以逗号分隔)。 |
| subject | string | 否 | 邮件主题。 |
| body | string | 否 | 邮件内容。 |
| ability.params.stream | string[ ] | 否 | 邮件附件(附件的uri地址列表)。 |
| ability.want.params.uriPermissionFlag | wantConstant.Flags | 否 | 给邮件附件赋予至少读权限。邮件附件参数存在时,该参数也必须要传。 |
| sceneType | number | 否 | 意图场景,表明本次请求对应的操作意图。1:发邮件。默认为1。 |
拉起方开发步骤:导入相关模块。构造接口参数并调用startAbilityByType接口。
import { common, wantConstant } from '@kit.AbilityKit';
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let wantParam: Record<string, Object> = {
'sceneType': 1,
'email': [encodeURI('xxx@example.com'), encodeURI('xxx@example.com')], // 收件人邮箱地址,多值以逗号分隔,对数组内容使用encodeURI()方法进行url编码
'cc': [encodeURI('xxx@example.com'), encodeURI('xxx@example.com')], // 抄送人邮箱地址,多值以逗号分隔,对数组内容使用encodeURI()方法进行url编码
'bcc': [encodeURI('xxx@example.com'), encodeURI('xxx@example.com')], // 密送人邮箱地址,多值以逗号分隔,对数组内容使用encodeURI()方法进行url编码
'subject': encodeURI('邮件主题'), // 邮件主题,对内容使用encodeURI()方法进行url编码
'body': encodeURI('邮件正文'), // 邮件正文,对内容使用encodeURI()方法进行url编码
'ability.params.stream': [encodeURI('附件uri1'), encodeURI('附件uri2')], // 附件uri,多值以逗号分隔,对数组内容使用encodeURI()方法进行url编码
'ability.want.params.uriPermissionFlag': wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION
};
let abilityStartCallback: common.AbilityStartCallback = {
onError: (code: number, name: string, message: string) => {
console.error(`onError code ${code} name: ${name} message: ${message}`);
},
onResult: (result) => {
console.info(`onResult result: ${JSON.stringify(result)}`);
}
}
context.startAbilityByType("mail", wantParam, abilityStartCallback,
(err) => {
if (err) {
console.error(`startAbilityByType fail, err: ${JSON.stringify(err)}`);
} else {
console.info(`success`);
}
});
拉起邮件类应用(mailto方式)
developer.huawei.com/consumer/cn…
mailto协议标准格式如下:
mailto:地址?参数=值
mailto:someone@example.com?key1=value1&key2=value2
mailto::mailto scheme,必填。
someone@example.com:收件人地址,选填。如果存在多个地址,用英文逗号分隔。
?:邮件头声明开始符号。如果带邮件头参数,则必填。
key-value:邮件头参数,详细参数见下表。
邮件头参数表
| 邮件头 | 含义 | 数据类型 | 是否必填 |
|---|---|---|---|
| subject | 邮件主题 | string | 否 |
| body | 邮件正文 | string | 否 |
| cc | 抄送人,多个用逗号分隔 | string | 否 |
| bcc | 密送人,多个用逗号分隔 | string | 否 |
拉起方开发步骤:把mailto字符串传入uri参数,开发时需要将邮箱地址替换为真实的邮箱,邮件内容根据需要进行配置。
let ctx = this.getUIContext().getHostContext() as common.UIAbilityContext;
ctx.startAbility({
action: 'ohos.want.action.sendToData',
uri: 'mailto:feedback@example.com?subject=App Feedback&body=Please describe your feedback here...'
})
拉起金融类应用实现支付场景(startAbilityByType)
developer.huawei.com/consumer/cn…
接口中type字段为finance,对应的wantParam参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| sceneType | number | 否 | 意图场景,表明本次请求对应的操作意图。1:转账汇款 2:信用卡还款。默认为1 |
| bankCardNo | string | 否 | 银行卡卡号 |
拉起方开发步骤:导入相关模块。构造接口参数并调用startAbilityByType接口。
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let wantParam: Record<string, Object> = {
'sceneType': 1,
"bankCardNo": '123456789'
};
拉起航班类应用(startAbilityByType)
developer.huawei.com/consumer/cn…
接口中type字段为flight,支持按航班号查询、按起降地查询两种意图场景,wantParam参数如下:
按航班号查询场景
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| sceneType | number | 否 | 意图场景,表明本次请求对应的操作意图。默认为1,按航班号查询场景填1或不填。 |
| flightNo | string | 是 | 航班号,航司二位代码+数字。 |
| departureDate | string | 否 | 航班出发时间:YYYY-MM-DD。 |
按起降地查询场景
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| sceneType | number | 是 | 意图场景,表明本次请求对应的操作意图。按起降地查询场景填2。 |
| originLocation | string | 是 | 出发地。 |
| destinationLocation | string | 是 | 目的地。 |
| departureDate | string | 否 | 航班出发时间:YYYY-MM-DD。 |
拉起方开发步骤:导入相关模块。构造接口参数并调用startAbilityByType接口。
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let wantParam: Record<string, Object> = {
'sceneType': 1,
'flightNo': 'ZH1509',
'departureDate': '2024-10-01'
};
let abilityStartCallback: common.AbilityStartCallback = {
onError: (code: number, name: string, message: string) => {
console.error(`onError code ${code} name: ${name} message: ${message}`);
},
onResult: (result) => {
console.info(`onResult result: ${JSON.stringify(result)}`);
}
}
context.startAbilityByType("flight", wantParam, abilityStartCallback,
(err) => {
if (err) {
console.error(`startAbilityByType fail, err: ${JSON.stringify(err)}`);
} else {
console.info(`success`);
}
});
拉起快递类应用(startAbilityByType)
developer.huawei.com/consumer/cn…
接口中type字段为express,支持查询快递意图,对应的wantParam参数如下:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| sceneType | number | 否 | 意图场景,表明本次请求对应的操作意图。默认为1,查询快递场景填1或不填。 |
| expressNo | string | 是 | 快递单号。 |
拉起方开发步骤:导入相关模块。构造接口参数并调用startAbilityByType接口。
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let wantParam: Record<string, Object> = {
'sceneType': 1,
'expressNo': 'SF123456'
};
let abilityStartCallback: common.AbilityStartCallback = {
onError: (code: number, name: string, message: string) => {
console.error(`onError code ${code} name: ${name} message: ${message}`);
},
onResult: (result) => {
console.info(`onResult result: ${JSON.stringify(result)}`);
}
}
context.startAbilityByType("express", wantParam, abilityStartCallback,
(err) => {
if (err) {
console.error(`startAbilityByType fail, err: ${JSON.stringify(err)}`);
} else {
console.info(`success`);
}
});
拉起图片编辑类应用(startAbilityByType)
developer.huawei.com/consumer/cn…
接口中type字段为imageEdit ,接口说明如下:
| 接口名 | 描述 |
|---|---|
| onStartContentEditing(uri: string, want:Want, session:UIExtensionContentSession):void | 可以执行读取原始图片、加载页面等操作。 |
| saveEditedContentWithImage(pixeMap: image.PixelMap, option:image.PackingOption): Promise < AbilityResult > | 传入编辑过的图片的PixelMap对象并保存。 |
拉起文件处理类应用(startAbility)
developer.huawei.com/consumer/cn…
startAbility请求中want相关参数说明:
| 参数名称 | 类型 | 是否必填 | 说明 |
|---|---|---|---|
| uri | string | 是 | 表示待打开文件的URI路径,一般配合type使用。uri格式为:file://bundleName/path- file:文件URI的标志。- bundleName:该文件资源的属主。- path:文件资源在应用沙箱中的路径。 |
| type | string | 否 | 表示打开文件的类型,推荐使用UTD类型,比如:'general.plain-text'、'general.image'。目前也可以兼容使用MIME type类型,如:'text/xml'、'image/'等。说明:1. type为可选字段,如果不传type,系统会尝试根据uri后缀名判断文件类型进行匹配;如果传入type,必须确保与uri的文件类型一致,否则会导致无法匹配到合适的应用。文件后缀与文件类型的映射关系参见Uniform Type Descriptor(UTD)预置列表。2. 不支持传/*。 |
| parameters | Record<string, Object> | 否 | 表示由系统定义,由开发者按需赋值的自定义参数,文件打开场景请参考表2。 |
| flags | number | 否 | 表示处理方式,文件打开场景请参考表3。 |
| action | string | 是 | 表示要执行的通用操作。文件打开场景固定值:'ohos.want.action.viewData' ,表示查看数据的操作。 |
3、拉起系统应用
developer.huawei.com/consumer/cn…
➢ 权限设置:通过requestPermissionsFromUser()接口拉起权限申请弹框时,如果用户拒绝授权,将 无法使用该接口再次拉起弹框,需要调用requestPermissionOnSetting接口拉起权限设置弹窗。
➢ 通知管理: 通过requestEnableNotification()接口拉起通知授权弹框时,如果用户拒绝授权,将无 法使用该接口再次拉起弹框,需要调用openNotificationSettings()接口,支持拉起通知管理弹窗。
➢ 网络管理:通过openNetworkManagerSettings()接口拉起WLAN设置弹窗。
➢ 应用市场:通过loadProduct()接口、App Linking等多种方式拉起应用详情页。
➢ 钱包:通过requestPayment()接口实现单次支付、支付并签约。
➢ 电话:通过makeCall()接口跳转到拨号界面,并显示待拨出的号码。
➢ 日历:通过addEvent接口创建日程。
➢ 联系人:通过联系人Picker(Contacts Picker),拉起联系人应用,读取联系人数据。
➢ 地图:通过地图Picke拉起地点详情展示、地点选取、区划选择。
➢ 拍照录像:通过相机Picker实现拍照、录像。
➢ 扫码 :通过扫码Picker调用相机,实现默认界面扫码。
➢ 卡证识别:通过卡证识别Picker调用相机,识别各类证件并提取卡证信息。
➢ 文档扫描 :通过文档扫描Picker调用相机,拍摄文档并转化为高清扫描件。
➢ 文件管理:文件Picker(DocumentViewPicker)用于访问、保存公共目录中文档类文件;音频 Picker(AudioViewPicker):用于访问、保存公共目录的音频文件。
➢ 图库(媒体库):通过照片Picker访问、保存公共目录的图片或视频文件。
案例:使用openLink接口和startAbility两种方式实现应用跳转
新建项目MyApplication1、MyApplication2
Index.ets (MyApplication1)
import { common, OpenLinkOptions, Want } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { cameraPicker } from '@kit.CameraKit';
import { camera } from '@kit.CameraKit';
const TAG: string = '[UIAbilityComponentsOpenLink]';
const DOMAIN_NUMBER: number = 0xFF00;
@Entry
@Component
struct Index {
build() {
Column({ space: 20 }) {
Button('openLink接口实现应用跳转', { type: ButtonType.Capsule, stateEffect: true })
.width('87%')
.height('5%')
.margin({ top: '20vp' })
.onClick(() => {
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let link: string = "link://www.example.com";
let openLinkOptions: OpenLinkOptions = {
appLinkingOnly: false
};
try {
context.openLink(link, openLinkOptions)
.then(() => {
hilog.info(DOMAIN_NUMBER, TAG, 'openLink success.');
}).catch((err: BusinessError) => {
hilog.error(DOMAIN_NUMBER, TAG, `openLink failed. Code is ${err.code}, message is ${err.message}`);
});
} catch (paramError) {
hilog.error(DOMAIN_NUMBER, TAG,
`Failed to start link. Code is ${paramError.code}, message is ${paramError.message}`);
}
})
Button('startAbility接口实现应用跳转', { type: ButtonType.Capsule, stateEffect: true })
.width('87%')
.height('5%')
.margin({ top: '20vp' })
.onClick(() => {
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let want: Want = {
uri: "link://www.example.com"
};
try {
context.startAbility(want).then(() => {
hilog.info(DOMAIN_NUMBER, TAG, 'startAbility success.');
}).catch((err: BusinessError) => {
hilog.error(DOMAIN_NUMBER, TAG, `startAbility failed. Code is ${err.code}, message is ${err.message}`);
});
} catch (paramError) {
hilog.error(DOMAIN_NUMBER, TAG,
`Failed to start ability. Code is ${paramError.code}, message is ${paramError.message}`);
}
})
}.width('100%').height('100%').justifyContent(FlexAlign.Center)
}
}
module.json5 (MyApplication2)
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"ohos.want.action.home"
],
},
{
"actions": [
// actions不能为空,actions为空会造成目标方匹配失败。
"ohos.want.action.viewData"
],
"uris": [
{
// scheme必选,可以自定义,以link为例,需要替换为实际的scheme
"scheme": "link",
// host必选,配置待匹配的域名
"host": "www.example.com"
}
]
} // 新增一个skill对象,用于跳转场景。如果存在多个跳转场景,需配置多个skill对象。
]
案例:拉起指定类型的应用(导航类)
Index.ets (MyApplication1)
// 路线规划功能 'sceneType': 1, 导航功能 'sceneType': 2, 位置搜索功能 'sceneType': 3,
Button('拉起导航类应用(路线规划页面)', { type: ButtonType.Capsule, stateEffect: true })
.width('87%')
.height('5%')
.margin({ top: '20vp' })
.onClick(() => {
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let wantParam: Record<string, Object> = {
'sceneType': 1,
'destinationLatitude': 32.060844,
'destinationLongitude': 118.78315,
'destinationName': 'xx市xx路xx号',
'destinationPoiIds': {
1: '1001', // key为1代表花瓣地图,value需为花瓣地图POI
2: '2002', // key为2代表高德地图,value需为高德地图POI
3: '3003' // key为3代表百度地图,value需为百度地图POI
} as Record<number, string>,
'originName': 'xx市xx公园',
'originLatitude': 31.060844,
'originLongitude': 120.78315,
'originPoiIds': {
1: '1101', // key为1代表花瓣地图,value需为花瓣地图POI
2: '2202', // key为2代表高德地图,value需为高德地图POI
3: '3303' // key为3代表百度地图,value需为百度地图POI
} as Record<number, string>,
'vehicleType': 0
};
let abilityStartCallback: common.AbilityStartCallback = {
onError: (code: number, name: string, message: string) => {
console.error(`onError code ${code} name: ${name} message: ${message}`);
},
onResult: (result) => {
console.info(`onResult result: ${JSON.stringify(result)}`);
}
}
context.startAbilityByType("navigation", wantParam, abilityStartCallback,
(err) => {
if (err) {
console.error(`startAbilityByType fail, err: ${JSON.stringify(err)}`);
} else {
console.info(`success`);
}
});
});
新建项目MyApplication3,并创建三个页面RoutePlanPage、NavigationPage、PlaceSearchPage
@Entry
@Component
struct RoutePlanPage {
build() {
Row() {
Column() {
Text('这是路径规划页面')
.fontSize($r('app.float.page_text_font_size'))
.fontWeight(FontWeight.Bold)
}
.width('100%')
}
.height('100%')
}
}
@Entry
@Component
struct NavigationPage {
build() {
Row() {
Column() {
Text('这是导航页面')
.fontSize($r('app.float.page_text_font_size'))
.fontWeight(FontWeight.Bold)
}
.width('100%')
}
.height('100%')
}
}
@Entry
@Component
struct PlaceSearchPage {
build() {
Row() {
Column() {
Text('这是置搜索页面')
.fontSize($r('app.float.page_text_font_size'))
.fontWeight(FontWeight.Bold)
}
.width('100%')
}
.height('100%')
}
}
resources/base/profile/main_pages.json (MyApplication3)
{
"src": [
"pages/Index",
"pages/RoutePlanPage",
"pages/PlaceSearchPage",
"pages/NavigationPage"
]
}
module.json5 (MyApplication3)
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"ohos.want.action.home"
]
},
{
"actions": [
// actions不能为空,actions为空会造成目标方匹配失败。
"ohos.want.action.viewData"
]
}, // 新增一个skill对象,用于跳转场景。如果存在多个跳转场景,需配置多个skill对象。
// 导航场景
{
"uris": [
{
"scheme": "maps", // 这里仅示意,应用需确保这里声明的uri能被外部正常拉起
"host": "navigation",
"path": "",
"linkFeature": "Navigation" // 声明应用支持导航功能
},
{
"scheme": "maps", // 这里仅示意,应用需确保这里声明的uri能被外部正常拉起
"host": "routePlan",
"path": "",
"linkFeature": "RoutePlan" // 声明应用支持路线规划功能
},
{
"scheme": "maps", // 这里仅示意,应用需确保这里声明的uri能被外部正常拉起
"host": "search",
"path": "",
"linkFeature": "PlaceSearch" // 声明应用支持位置搜索功能
}
]
}
]
EntryAbility.ets (MyApplication3)
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
export default class EntryAbility extends UIAbility {
windowStage: window.WindowStage | null = null;
uri?: string;
destinationLatitude?: number;
destinationLongitude?: number;
destinationName?: string;
originName?: string;
originLatitude?: number;
originLongitude?: number;
vehicleType?: number;
destinationPoiId?: string;
originPoiId?: string;
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
super.onCreate(want, launchParam);
this.parseWant(want);
}
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
super.onNewWant(want, launchParam);
this.parseWant(want);
if (!this.windowStage) {
this.context.terminateSelf();
return;
}
this.loadPage(this.windowStage);
}
private parseWant(want: Want): void {
this.uri = want.uri as string | undefined;
this.destinationLatitude = want.parameters?.destinationLatitude as number | undefined;
this.destinationLongitude = want.parameters?.destinationLongitude as number | undefined;
this.destinationName = want.parameters?.destinationName as string | undefined;
this.originName = want.parameters?.originName as string | undefined;
this.originLatitude = want.parameters?.originLatitude as number | undefined;
this.originLongitude = want.parameters?.originLongitude as number | undefined;
this.vehicleType = want.parameters?.vehicleType as number | undefined;
this.destinationPoiId = want.parameters?.destinationPoiId as string | undefined;
this.originPoiId = want.parameters?.originPoiId as string | undefined;
}
private loadPage(windowStage: window.WindowStage): void {
if (this.uri === 'maps://navigation') {
// 构建导航场景参数
const storage: LocalStorage = new LocalStorage({
"destinationLatitude": this.destinationLatitude,
"destinationLongitude": this.destinationLongitude,
"destinationPoiId": this.destinationPoiId
} as Record<string, Object>);
// 拉起导航页面
windowStage.loadContent('pages/NavigationPage', storage)
} else if (this.uri === 'maps://routePlan') {
// 构建路径规划场景参数
const storage: LocalStorage = new LocalStorage({
"destinationLatitude": this.destinationLatitude,
"destinationLongitude": this.destinationLongitude,
"destinationName": this.destinationName,
"originName": this.originName,
"originLatitude": this.originLatitude,
"originLongitude": this.originLongitude,
"vehicleType": this.vehicleType,
"destinationPoiId": this.destinationPoiId,
"originPoiId": this.originPoiId
} as Record<string, Object>);
// 拉起路径规划页面
windowStage.loadContent('pages/RoutePlanPage', storage)
} else if (this.uri === 'maps://search') {
// 构建位置搜索场景参数
const storage: LocalStorage = new LocalStorage({
"destinationName": this.destinationName
} as Record<string, Object>);
// 拉起位置搜索页面
windowStage.loadContent('pages/PlaceSearchPage', storage)
} else {
// 默认拉起首页
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
return;
}
});
}
}
onDestroy(): void {
}
onWindowStageCreate(windowStage: window.WindowStage): void {
this.windowStage = windowStage;
this.loadPage(this.windowStage);
}
onWindowStageDestroy(): void {
}
onForeground(): void {
}
onBackground(): void {
}
}
案例:演示拉起系统中的相机应用
Index.ets (MyApplication1)
@State uri: Resource | string | undefined = undefined;
private cameraPosition: Array<camera.CameraPosition> = [
camera.CameraPosition.CAMERA_POSITION_UNSPECIFIED, camera.CameraPosition.CAMERA_POSITION_BACK,
camera.CameraPosition.CAMERA_POSITION_FRONT
];
private mediaType: Array<cameraPicker.PickerMediaType> = [
cameraPicker.PickerMediaType.PHOTO, cameraPicker.PickerMediaType.VIDEO
];
Button('拉起系统应用中的相机')
.width('87%')
.height('5%')
.margin({ top: '20vp' })
.onClick(async () => {
try {
// 配置以启动后置摄像头
let pickerProfile: cameraPicker.PickerProfile = { cameraPosition: this.cameraPosition[1] };
// 配置为拍照模式
let pickerResult: cameraPicker.PickerResult = await cameraPicker.pick(this.getUIContext().getHostContext(),
[this.mediaType[0]], pickerProfile);
// 获取视频URI
this.uri = pickerResult.resultUri;
hilog.info(0x0000, ' ', "the pick pickerResult is:" + JSON.stringify(pickerResult));
} catch (error) {
let err = error as BusinessError;
hilog.error(0x0000, '', `the pick call failed. error code: ${err.code}`);
}
})