OpenHarmony应用开发进阶 - 隐式Want的匹配规则源码解析(一)
Want对象用于在应用组件之间传递信息,常见的使用场景为startAbility方法的参数。本文将基于包管理框架源码向大家介绍隐式Want和基础匹配规则。
概述
文档环境
DevEco Studio 版本:DevEco Studio 5.0.2 Release(5.0.7.200)
SDK 版本:5.0.2 (API14)
开发板型号:DAYU 200
系统版本:OpenHarmony-5.0.2-Release
涉及仓库:bundlemanager_bundle_framework
功能简介
- Want对象用于在应用组件之间传递信息,常见的使用场景为startAbility方法的参数。例如,当UIAbility-A需要启动UIAbility-B并向UIAbility-B传递一些数据时,可以使用Want作为一个载体,将数据传递给UIAbility-B。
- 在启动目标应用组件时,通过显式Want或者隐式Want进行目标应用组件的匹配:
显式Want:在启动目标应用组件时,调用方传入的want参数中指定了abilityName和bundleName,称为显式Want。
隐式Want:在启动目标应用组件时,调用方传入的want参数中未指定abilityName,称为隐式Want。
- 本文将基于包管理框架源码向大家介绍隐式Want和基础匹配规则,在隐式Want的匹配规则源码解析(二)中将详细的介绍隐式Want的匹配规则。
隐式Want匹配规则
隐式Want的定义
在启动目标应用组件时,调用方传入的want参数中未指定abilityName,称为隐式Want。
从隐式Want的定义,可得知:
- 调用方传入的want参数,表明调用方需要执行的操作,并提供相关数据以及其他应用类型限制。
- 待匹配应用组件的skills配置,声明其具备的能力(module.json5配置文件中的skills标签参数)。
系统将调用方传入的want参数(包含action、entities、uri、type和parameters属性)与已安装待匹配应用组件的skills配置(包含actions、entities、uris和type属性)进行匹配。当want参数五个属性匹配均未配置,隐式匹配失败。
Want的启动规则
当应用需要处理业务的目标应用不明确时,可以使用隐式Want,而不关心提供该能力的具体应用。隐式Want使用Skills标签来定义需要使用的能力,并由系统匹配声明支持该请求的所有应用来处理业务。例如,需要打开一个链接的业务,系统将匹配所有声明支持该请求的应用,然后让用户选择使用哪个应用打开链接。
let wantInfo: Want = {
uri: 'https://www.example.com/',
};
根据系统中待匹配应用组件的匹配情况不同,使用隐式Want启动应用组件时会出现以下三种情况。
- 未匹配到满足条件的应用组件:启动失败。
- 匹配到一个满足条件的应用组件:直接启动该应用组件。
- 匹配到多个满足条件的应用组件(UIAbility):弹出选择框让用户选择。
基础匹配规则
在详细讲解隐式want匹配的规则前,我们先了解一下URI和Type的基础匹配规则。
URI匹配规则
为了简化描述,称调用方传入的want中uri参数为w_uri;待匹配应用的skills配置中uris为s_uris,其中每个元素为s_uri。
匹配规则:
- 规则U-1:当w_uri和s_uri的scheme均为空时,匹配成功,否则进行下一条规则匹配。
- 规则U-2:当w_uri和s_uri的scheme有一个参数为空时,匹配失败,否则进行下一条规则匹配。
- 规则U-3:如果s_uri的host为空,当w_uri和s_uri的scheme相同时,匹配成功,否则匹配失败。
注:如果s_uri的host不为空,进行下一条规则匹配。
- 规则U-4:如果s_uri的path、pathStartWith和pathRegex为空,当w_uri包含s_uri中的scheme、host和port拼接后的字符或相同时,匹配成功,否则匹配失败。
注:如果s_uri的path、pathStartWith和pathRegex有一个参数不为空,进行下一条规则匹配。
- 规则U-5:如果s_uri的path不为空,当w_uri和s_uri全路径表达式相同时,匹配成功,否则进行下一条规则匹配。
注:如果s_uri的path为空,进行下一条规则匹配。
- 规则U-6:如果s_uri的pathStartWith不为空,当w_uri包含s_uri前缀表达式时匹配成功,否则进行下一条规则匹配。
注:如果s_uri的pathStartWith为空,进行下一条规则匹配。
- 规则U-7:如果s_uri的pathRegex不为空,当w_uri满足s_uri正则表达式时匹配成功,否则匹配失败。
注:如果配置pathRegex,则全路径支持正则表达式匹配。当匹配失败时,URI匹配失败。
// interfaces/inner_api/appexecfwk_base/src/skill.cpp
bool Skill::MatchUri(const std::string &uriString, const SkillUri &skillUri) const
{
// 规则U-1:当w_uri和s_uri的scheme均为空时,匹配成功,否则进行下一条规则匹配。
if (uriString.empty() && skillUri.scheme.empty()) {
return true;
}
// 规则U-2:当w_uri和s_uri的scheme有一个参数为空时,匹配失败,否则进行下一条规则匹配。
if (uriString.empty() || skillUri.scheme.empty()) {
return false;
}
// 规则U-3:如果s_uri的host为空,当w_uri和s_uri的scheme相同时,匹配成功,否则匹配失败。
if (skillUri.host.empty()) {
return uriString == skillUri.scheme || StartsWith(uriString, skillUri.scheme + PORT_SEPARATOR);
}
std::string optParamUri = GetOptParamUri(uriString);
std::string skillUriString;
skillUriString.append(skillUri.scheme).append(SCHEME_SEPARATOR).append(skillUri.host);
if (!skillUri.port.empty()) {
skillUriString.append(PORT_SEPARATOR).append(skillUri.port);
}
// 规则U-4:如果s_uri的path、pathStartWith和pathRegex为空,当w_uri包含s_uri中的scheme、host和port拼接后的字符或相同时,匹配成功,否则匹配失败。
if (skillUri.path.empty() && skillUri.pathStartWith.empty() && skillUri.pathRegex.empty()) {
bool ret = (optParamUri == skillUriString || StartsWith(optParamUri, skillUriString + PATH_SEPARATOR));
if (skillUri.port.empty()) {
ret = ret || StartsWith(optParamUri, skillUriString + PORT_SEPARATOR);
}
return ret;
}
skillUriString.append(PATH_SEPARATOR);
// 规则U-5:如果s_uri的path不为空,当w_uri和s_uri全路径表达式相同时,匹配成功。
if (!skillUri.path.empty()) {
std::string pathUri(skillUriString);
pathUri.append(skillUri.path);
if (optParamUri == pathUri) {
return true;
}
}
// 规则U-6:如果s_uri的pathStartWith不为空,当w_uri包含s_uri前缀表达式时匹配成功,否则进行下一条规则匹配。
if (!skillUri.pathStartWith.empty()) {
std::string pathStartWithUri(skillUriString);
pathStartWithUri.append(skillUri.pathStartWith);
if (StartsWith(optParamUri, pathStartWithUri)) {
return true;
}
}
// 规则U-7:如果s_uri的pathRegex不为空,当w_uri满足s_uri正则表达式时匹配成功,否则匹配失败。
if (!skillUri.pathRegex.empty()) {
std::string pathRegexUri(skillUriString);
pathRegexUri.append(skillUri.pathRegex);
try {
std::regex regex(pathRegexUri);
if (regex_match(optParamUri, regex)) {
return true;
}
} catch (const std::regex_error& e) {
APP_LOGE("regex error");
}
}
return false;
}
Type匹配规则
为了简化描述,称调用方传入的want参数的type参数为w_type,待匹配应用组件的skills数组中uris的type数据为s_type。
匹配规则:
- 规则T-1:当s_type和w_type均为空时,匹配成功,否则进行下一条规则匹配。
- 规则T-2:当s_type和w_type有一个参数为空时,匹配失败,否则进行下一条规则匹配。
- 规则T-3:如果w_type为reserved/wildcard,当s_type为*/*或者general.object时,匹配成功,否则匹配失败。
注:如果w_type不为reserved/wildcard,进行下一条规则匹配。
- 规则T-4:如果w_type和u_type中一个满足UTD规则,进行UTD匹配,返回UTD匹配结果。
注:如果w_type和u_type不满足UTD规则,进行下一条规则匹配。
- 规则T-5:当s_type或者w_type为通配符*/*时,匹配成功,否则进行下一条规则匹配。
- 规则T-6:如果w_type最后一个字符为通配符*,如prefixType/*,当s_type包含prefixType/时匹配成功,否则匹配失败。
注:如果w_type最后一个字符不为通配符*,进行下一条规则匹配。
- 规则T-7:如果s_type最后一个字符为通配符*,如prefixType/*,则当w_type包含prefixType/时匹配成功,否则匹配失败。
注:如果s_type最后一个字符不为通配符*,进行下一条规则匹配。
- 规则T-8:当w_type和s_type相同时匹配成功,否则匹配失败。
// interfaces/inner_api/appexecfwk_base/src/skill.cpp
bool Skill::MatchType(const std::string &type, const std::string &skillUriType) const
{
// 规则T-1:当s_type和w_type均为空时,匹配成功,否则进行下一条规则匹配。
if (type.empty() && skillUriType.empty()) {
return true;
}
// 规则T-2:当s_type和w_type有一个参数为空时,匹配失败,否则进行下一条规则匹配。
if (type.empty() || skillUriType.empty()) {
return false;
}
// TYPE_ONLY_MATCH_WILDCARD = "reserved/wildcard";
// TYPE_WILDCARD = "*/*";
// GENERAL_OBJECT = "general.object";
//
// 规则T-3:如果w_type为reserved/wildcard,当s_type为*/*或者general.object时,匹配成功,否则匹配失败。
if (type == TYPE_ONLY_MATCH_WILDCARD) {
return skillUriType == TYPE_WILDCARD || skillUriType == GENERAL_OBJECT;
}
bool containsUtd = false;
// 规则T-4:如果w_type和u_type中一个满足UTD规则,进行UTD匹配,返回UTD匹配结果。
bool matchUtdRet = MatchUtd(type, skillUriType, containsUtd);
if (containsUtd) {
return matchUtdRet;
}
// 规则T-5:当s_type或者w_type为通配符*/*时,匹配成功,否则进行下一条规则匹配。
if (type == TYPE_WILDCARD || skillUriType == TYPE_WILDCARD) {
return true;
}
// 规则T-6:如果w_type最后一个字符为通配符*,如prefixType/*,当w_type包含prefixType/时匹配成功,否则匹配失败。
bool paramTypeRegex = type.back() == WILDCARD;
if (paramTypeRegex) {
std::string prefix = type.substr(0, type.length() - 1);
return skillUriType.find(prefix) == 0;
}
bool typeRegex = skillUriType.back() == WILDCARD;
if (typeRegex) {
// 规则T-7:如果s_type最后一个字符为通配符*,如prefixType/*,则当w_type包含prefixType/时匹配成功,否则匹配失败。
std::string prefix = skillUriType.substr(0, skillUriType.length() - 1);
return type.find(prefix) == 0;
} else {
// 规则T-8:当w_type和s_type相同时匹配成功,否则匹配失败。
return type == skillUriType;
}
}
隐式Want匹配基本规则
- 规则1:如果parameters中的linkFeature字段取值不为空,进行linkFeature匹配,返回linkFeature匹配的结果。
注:如果parameters中的linkFeature字段取值为空,进行下一条规则匹配。
- 规则2:如果parameters中的linkFeature未配置时,只有当action、entities、uri和type四个属性均匹配成功则隐式匹配成功。
- 规则2.1:当want参数的action匹配失败时,隐式匹配失败,否则继续匹配。
- 规则2.2:当want参数的entities匹配失败时,隐式匹配失败,否则继续匹配。
- 规则2.3:当want参数的uri和type匹配失败时,隐式匹配失败。
// interfaces/inner_api/appexecfwk_base/src/skill.cpp
bool Skill::Match(const OHOS::AAFwk::Want &want) const
{
// 规则1:如果parameters中的linkFeature字段取值不为空,进行linkFeature匹配,返回linkFeature匹配的结果。
std::string linkFeature = want.GetStringParam(LINK_FEATURE);
if (!linkFeature.empty()) {
size_t matchUriIndex = 0;
return MatchLinkFeature(linkFeature, want, matchUriIndex);
}
// 规则2:如果parameters中的linkFeature未配置时,只有当action、entities、uri和type四个属性均匹配成功则隐式匹配成功。
// 规则2.1:当want参数的action匹配失败时,隐式匹配失败,否则继续匹配。
// 规则2.2:当want参数的entities匹配失败时,隐式匹配失败,否则继续匹配。
if (!MatchActionAndEntities(want)) {
APP_LOGD("Action or entities does not match");
return false;
}
// 规则2.3:当want参数的uri和type匹配失败时,隐式匹配失败。
std::vector<std::string> vecTypes = want.GetStringArrayParam(OHOS::AAFwk::Want::PARAM_ABILITY_URITYPES);
if (vecTypes.size() > 0) {
for (std::string strType : vecTypes) {
if (MatchUriAndType(want.GetUriString(), strType)) {
APP_LOGD("type %{public}s, Is Matched", strType.c_str());
return true;
}
}
return false;
}
bool matchUriAndType = MatchUriAndType(want.GetUriString(), want.GetType());
if (!matchUriAndType) {
APP_LOGD("Uri or Type does not match");
return false;
}
return true;
}
更多推荐
所有评论(0)