当前位置: 首页 > news >正文

HarmonyOS应用程序访问控制探究

关于作者

白晓明

宁夏图尔科技有限公司董事长兼CEO、坚果派联合创始人

华为HDE、润和软件HiHope社区专家、鸿蒙KOL、仓颉KOL

华为开发者学堂/51CTO学堂/CSDN学堂认证讲师

开放原子开源基金会2023开源贡献之星

一、引言

随着信息技术的飞速发展,移动应用程序已经成为人们生活和工作中不可或缺的一部分。然而,随之而来的是对应用程序安全性的更高要求,尤其在用户隐私保护方面。工信部一直高度重视用户隐私保护,并依据《个人信息保护法》、《电信条例》、《规范互联网信息服务市场秩序若干规定》、《电信和互联网用户个人信息保护规定》等相关法律法规规章,对涉及用户隐私获取做出明确的通知,防止未经用户授权访问用户隐私信息以及用户隐私信息的滥用。

HarmonyOS的应用程序访问控制机制在这种背景下显得尤为重要,不仅可以保护用户的个人信息,还可以提高应用程序的安全性和可靠性,增强用户对应用程序的信任。HarmonyOS应用程序中,默认情况下,应用只能访问有限的系统资源,需要访问额外的系统数据(包括用户个人数据)和功能,应用必须以明确的方式对外提供接口来共享其数据或功能。通过访问控制机制,避免数据或功能被不当或恶意使用。

我将继续深入探究HarmonyOS应用程序访问控制的原理、方法和实践,为开发者和用户提供有益的参考。通过对HarmonyOS访问控制机制的探究,我们可以更好地理解其工作原理和优势,为开发更加安全可靠的应用程序提供指导。同时,我们也可以为用户提供更好的使用体验,让用户更加放心地使用HarmonyOS应用程序。

二、HarmonyOS应用程序访问控制的重要性

1)保护用户数据安全

在移动应用程序中,用户的数据往往包含敏感信息,如个人身份信息、财务信息等。如果应用程序没有有效的访问控制机制,这些数据可能会被恶意应用程序窃取或滥用。HarmonyOS的访问控制机制可以限制应用程序对用户数据的访问权限,从而保护用户数据的安全。HarmonyOS根据不同的授权方式,权限类型分为以下两种:

  • system_grant(系统授权):在该类型的权限许可下,应用被允许访问的数据不会涉及到用户或设备的敏感信息,应用被允许执行的操作对系统或者其他应用产生的影响可控。申请该权限的应用系统会在用户安装应用时,自动把相应权限授予应用。

  • user_grant(用户授权):在该类型的权限许可下,应用被允许访问的数据将会涉及到用户或设备的敏感权限,应用被允许执行的操作可能对系统或其他应用产生严重的影响。该类型权限不仅需要在安装包中申请权限,还需要在应用动态运行时,通过发送弹窗的方式请求用户授权。在用户手动允许授权后,应用才会真正获取相应的权限,从而成功访问操作目标对象。

2)防止应用程序滥用权限

一些应用程序可能会过度申请权限,从而获取用户的隐私信息或进行不必要的操作。HarmonyOS的访问控制机制可以对应用程序的权限进行严格管理,防止应用程序滥用权限。HarmonyOS提出了受限开放的权限,比如允许读写用户公共目录的音频文件ohos.permission.READ_AUDIO/WRITE_AUDIO,允许应用使用全局悬浮窗的能力ohos.permission.SYSTEM_FLOAT_WINDOW等权限,若特殊场景需要使用这些受限开放权限,则需要提供相关申请材料到应用市场申请相应权限证书通过后,才可以正常使用。

3)提高系统安全性

HarmonyOS的访问控制机制不仅可以保护用户数据的安全,还可以提高系统的安全性。通过限制应用程序的访问权限,可以防止恶意应用程序对系统进行攻击或破坏。

三、HarmonyOS应用程序访问控制的原理

1)应用权限

HarmonyOS采用了权限管理机制,对应用程序的访问权限进行严格控制。应用程序在安装时需要声明所需的权限,用户在安装应用程序时可以查看这些权限并决定是否授予。在运行时,系统会根据应用程序的权限声明和用户的授权情况,对应用程序的访问请求进行权限检查。

为了防止应用过度索取和滥用权限,HarmonyOS中基于APL(Ability Privilege Level,元能力权限等级)等级,配置了不同的权限开放范围。应用APL等级分为以下三个等级,等级依次提高。

APL级别说明
normal默认情况下,应用的APL等级都是normal等级。
system_basic该等级的应用服务提供系统基础服务。
system_core该等级的应用服务提供操作系统核心能力。应用APL等级不允许配置为system_core。

根据权限对于不同等级应用有不同的开放范围,权限APL等级对应分为以下三个等级,等级依次提高。

APL级别说明开放范围
normal允许应用访问超出默认规则的普通系统资源,如配置Wi-Fi信息、调用相机拍摄等。 这些系统资源的开放(包括数据和功能)对用户隐私以及其他应用带来的风险低。APL等级为normal及以上的应用。
system_basic允许应用访问操作系统基础服务(系统提供或者预置的基础功能)相关的资源,如系统设置、身份认证等。 这些系统资源的开放对用户隐私以及其他应用带来的风险较高。- APL等级为system_basic及以上的应用。 - 部分权限对normal级别的应用受限开放,需要额外申请。
system_core涉及开放操作系统核心资源的访问操作。这部分系统资源是系统最核心的底层服务,如果遭受破坏,操作系统将无法正常运行。- APL等级为system_core的应用。 - 仅对系统应用开放。

2)沙箱机制

HarmonyOS采用了沙箱机制,系统中运行的应用程序均部署在受限保护的沙箱中,通过沙箱的安全隔离机制,可以限制应用程序的不当行为(如应用间非法访问数据、篡改设备等)。沙箱环境中每个程序都拥有唯一的ID(TokenID),系统基于此ID识别与限制应用的访问行为,从而提高系统的安全性。同时,沙箱机制还可以防止应用程序之间的互相干扰,提高系统的稳定性。

3)系统控件

HarmonyOS提供了系统Picker、安全控件等临时授权的方式替代权限申请,在特定的场景中,应用无需向用户申请权限也可以临时访问受限资源,实现精准化权限管控,更好地保护用户隐私。

  • 系统Picker:由系统独立进程实现,在应用拉起Picker,并由用户操作Picker后,应用可以获取Picker返回的资源或结果。举例说明,当应用需要读取用户图片时,可通过使用照片Picker,在用户选择所需要的图片资源后,直接返回该图片资源,而不需要授予应用读取图片文件的权限。

  • 安全控件:由系统提供UI控件,应用在界面内集成对应控件,用户点击后,应用将获得临时授权,从而执行相关操作。举例说明,当应用需要分享当前位置时,可使用位置控件,用户点击后,将会在本次前台期间获得精准定位的授权,可以调用位置服务获取精准定位。当发生灭屏、应用切后台、应用退出等任一情况时,临时授权结束。

四、 HarmonyOS应用程序访问控制开发指南

1)选择申请权限的方式

  • 最小权限原则:即在应用开发初期,开发者应仔细分析应用的功能和业务逻辑,确定所需的权限,避免过度申请权限,以免引起用户的疑虑和不信任。

  • 动态申请权限:即在应用运行时,根据实际业务场景动态申请权限,提高用户体验,减少不必要的权限请求干扰。

在HarmonyOS中每个权限的权限等级、授权方式不同,申请权限的方式也不同,开发者在申请权限前,需要先根据应用权限列表和应用申请权限的方式(参见下表)查看能否申请目标权限。

权限类型授权方式操作路径
所有应用可申请system_grant声明权限 > 访问接口
所有应用可申请user_grant声明权限 > 向用户申请授权 > 访问接口
受限开放权限system_grant申请使用受限权限 > 声明权限 > 访问接口
受限开放权限user_grant申请使用受限权限 > 声明权限 > 向用户申请授权 > 访问接口

以位置服务(Location Kit)为例,应用需要检查是否已经获取用户授权访问设备位置信息,若未获取授权,可以向用户申请需要的位置权限。

权限名称权限级别授权方式说明
ohos.permission.LOCATIONnormaluser_grant允许应用获取设备位置信息。 需要与模糊位置权限一起申请。
ohos.permission.APPROXIMATELY_LOCATIONnormalUser_grant允许应用获取设备模糊位置信息。

2)声明权限

根据实际的业务需要确定需要的权限后,需要在module.json5配置文件的requestPermissions标签中声明位置服务(Location Kit)所需的权限。

{"module": {..."requestPermissions": [{"name": "ohos.permission.LOCATION",	// 权限名称,为系统已定义的权限"reason": "$string:location_reason",	// 申请权限的原因,当申请权限为user_grant权限时该字段为必填"usedScene": {	// 用于描述权限使用场景,当申请权限为user_grant权限时该字段为必填"abilities": ["EntryAbility"],"when": "inuse"	// 调用时机(inuse:使用时;always:始终)}},{"name": "ohos.permission.APPROXIMATELY_LOCATION","reason": "$string:location_reason","usedScene": {"abilities": ["EntryAbility"],"when": "inuse"}}]}
}

3)向用户申请授权封装

大多数应用程序都会根据业务需要向用户申请授权,可利用抽象理念将向用户申请授权代码封装成可复用的模块或组件。通过定义清晰的接口和规范,可以提高代码的可维护性和可扩展性,同时降低不同应用场景的适配难度。

在工程entry模块src/main/ets目录下创建common文件夹,用于存放工程需要的基础公共代码,比如常量类AppConstants、权限控制工具类PermissionUtil等。

common > utils目录创建ArkTS文件PermissionUtil,并使用export导出该类。

/*** @description 权限控制工具类* @author 白晓明*/
export class PermissionUtil {
​
}

用户每次执行需要目标权限的操作时,应用都必须调用checkAccessToken()方法检查自身是否已经具有该权限,该方法返回已授权PERMISSION_GRANTED或未授权PERMISSION_DENIED。在PermissionUtil中添加静态方法checkPermissionGrant用于检查当前应用程序是否已经被授予权限。

/*** 校验应用是否被授予 {permission} 权限* @param permission* @returns*/
static checkPermissionGrant(permission: Permissions): abilityAccessCtrl.GrantStatus {const atManager = abilityAccessCtrl.createAtManager();// 初始化grantStatus为未授权let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;let tokenId: number = 0;try {// 获取应用程序的accessTokenIDconst bundleInfo: bundleManager.BundleInfo =bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);const appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;tokenId = appInfo.accessTokenId;// 校验应用是否被授予权限grantStatus = atManager.checkAccessTokenSync(tokenId, permission);console.log(`检查${permission}权限状态为:${grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED ? "未授权" : "已授权"}`);} catch (error) {const err = error as BusinessError;console.error(`检查${permission}权限异常:${JSON.stringify(err)}`);grantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;}return grantStatus;
}

在校验应用是否被授予权限时,若未授权,需要调用requestPermissionsFromUser()方法动态向用户申请权限(指应用程序运行时向用户请求授权的过程)。在PermissionUtil中添加静态方法reqPermissionFromUser方法动态向用户申请授权。

/*** 动态申请权限* @param permissions* @returns */
static async reqPermissionFromUser(permissions: Permissions[]): Promise<number[]> {console.log(`[AppLogger]动态申请权限开始`);const atManager = abilityAccessCtrl.createAtManager();let result: PermissionRequestResult = { permissions: [], authResults: [] };try {result = await atManager.requestPermissionsFromUser(context, permissions);} catch (error) {const err = error as BusinessError;console.error(`[AppLogger]动态申请权限异常:${JSON.stringify(err)}`);}return result.authResults;
}

4)在UI中向用户申请授权

import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit'
import { PermissionUtil } from '../common/utils/PermissionUtil';
​
@Entry
@Component
struct Index {
​private locationPermissions: Permissions[] = ['ohos.permission.LOCATION','ohos.permission.APPROXIMATELY_LOCATION'];
​async aboutToAppear(): Promise<void> {// 校验是否被授予定位权限let flag: boolean = false;for (const permission of this.locationPermissions) {flag = false;const grantStatus: abilityAccessCtrl.GrantStatus = PermissionUtil.checkPermissionGrant(permission);if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {flag = true;}}if (!flag) {  // 未授权,则弹出授权提示弹窗await PermissionUtil.reqPermissionFromUser(this.locationPermissions);}}
​build() {...}
}

5)效果预览

五、结论

HarmonyOS应用程序访问控制机制是保障用户数据安全和系统安全的重要手段。通过权限管理、沙箱机制、系统控件等多种方法,HarmonyOS可以有效地限制应用程序对系统资源的访问权限,防止应用程序滥用权限和恶意攻击。

相关文章:

HarmonyOS应用程序访问控制探究

关于作者 白晓明 宁夏图尔科技有限公司董事长兼CEO、坚果派联合创始人 华为HDE、润和软件HiHope社区专家、鸿蒙KOL、仓颉KOL 华为开发者学堂/51CTO学堂/CSDN学堂认证讲师 开放原子开源基金会2023开源贡献之星 一、引言 随着信息技术的飞速发展&#xff0c;移动应用程序已经成为…...

董卫民赴考拉悠然等企业调研,强调加快发展人工智能产业

8月14日&#xff0c;按照省政府重点产业链协同推进机制有关工作安排&#xff0c;省委常委、常务副省长董卫民在成都市调研人工智能产业发展情况&#xff0c;并召开座谈会。他强调&#xff0c;要坚决落实党的二十届三中全会精神和省委省政府决策部署&#xff0c;充分把握人工智能…...

MFC将类A中的事件在类B中处理采用回调函数实现

需求&#xff1a; 在类A的界面上有一个tab控件。tab控件上面有那个页面。在MFC编程中一个tab的一个页面就应该是一个新的类。在tab的一个页面上有一个list控件。现在需要将list控件的点击事件&#xff0c;双击事件等在类A里面处理。 解决&#xff1a; 在类B里面给控件list添加…...

公众号 微信登录

export function getWxCode(that, localhostUrl) { // localhostUrl 当前页面的路径 传这个也可以this.$route.fullPath// console.log(that.$store.state.wxSessionData)// console.log(that.$store.state.wxSessionData.openId)//openId为undefine执行获取openid判断是否没有…...

sanic + webSocket:股票实时行情推送服务实现

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storm…...

Unity动态给按钮各个状态下的图片赋值

Unity动态给按钮各个状态下的图片赋值 using UnityEngine; using UnityEngine.UI; public class ButtonOnClickTest : MonoBehaviour {public Button btn;public Sprite _highlighterSprite;public Sprite _pressedSprite;public Sprite _selectesdSprite;public Sprite _disa…...

xiaomi pad 6PRO 小米平板6 pro hyperOS降级 澎湃os 降级MIUI 14 教程 免解锁BL 降级,168小时解锁绑定

小米平板 6 Pro 机型代号 &#xff1a;liuqin 降级MIUI 14 小米澎湃 OS 正式版 澎湃OS安卓发布日期卡刷包线刷包OS1.0.7.0.UMYCNXM14.02024-07-13miui_LIUQIN_OS1.0.7.0.UMYCNXM_d618a5c980_14.0.zipliuqin_images_OS1.0.7.0.UMYCNXM_20240705.0000.00_14.0_cn_8cbf5920be.…...

MySQL 备份一个表

语法(创建一个与table1结构相同的新表table2&#xff0c;并且将table1的数据复制到table2)&#xff1a; create table table2 as select * from table1 举例(备份tb_log表到tb_log_20240815中去)&#xff1a; create table tb_log_20240815 as select * from tb_log...

鸿蒙开发入门day10-组件导航

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;还请三连支持一波哇ヾ(&#xff20;^∇^&#xff20;)ノ&#xff09; 目录 组件导航 (Navigation) 设置页面显示模式 设置标题栏模式 设置菜…...

虚拟机Linux的坑 | VMware无法从主机向虚拟机 跨系统复制粘贴拖动 文件/文本

这个情况下&#xff0c;还是没办法跨系统拖拽文件 解决办法&#xff1a; 在终端中输入命令 sudo apt-get autoremove open-vm-tools sudo apt-get install open-vm-tools sudo apt-get install open-vm-tools-desktop过程中只要需要选择是否覆盖的地方&#xff0c;都输入&…...

Chat App 项目之解析(二)

Chat App 项目介绍与解析&#xff08;一&#xff09;-CSDN博客文章浏览阅读76次。Chat App 是一个实时聊天应用程序&#xff0c;旨在为用户提供一个简单、直观的聊天平台。该应用程序不仅支持普通用户的注册和登录&#xff0c;还提供了管理员登录功能&#xff0c;以便管理员可以…...

数据结构与算法 - 双指针

一、移动零 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12]输出: [1,3,12,0,0]示例 2: 输入: nums …...

Python3网络爬虫开发实战(10)模拟登录(需补充账号池的构建)

文章目录 一、基于 Cookie 的模拟登录二、基于 JWT 模拟登入三、账号池四、基于 Cookie 模拟登录爬取实战五、基于JWT 的模拟登录爬取实战六、构建账号池 很多情况下&#xff0c;网站的一些数据需要登录才能查看&#xff0c;如果需要爬取这部分的数据&#xff0c;就需要实现模拟…...

SQL 调优最佳实践笔记

定义与重要性 SQL 调优&#xff1a;提高SQL性能&#xff0c;减少查询时间和资源消耗。目标&#xff1a;减少查询时间和扫描的数据行数。 基本原则 减少扫描行数&#xff1a;只扫描所需数据。使用合适索引&#xff1a;确保WHERE条件命中最优索引。合适的Join类型&#xff1a;…...

Eclipse的使用配置教程:必要设置、创建工程及可能遇到的问题(很详细,很全面,能解决90%的问题)

Eclipse的使用配置&#xff1a; Ⅰ、Eclipse 的必要配置&#xff1a;1、Eclipse 的安装&#xff1a;其一、将 Eclipse 解压或安装到没有中文且没有空格的路径下。其二、拿到 eclipse.exe 文件&#xff0c;傻瓜式安装即可; 2、设置工作空间(workspace)&#xff1a;其一、首次启动…...

遗传算法与深度学习实战(4)——遗传算法详解与实现

遗传算法与深度学习实战&#xff08;4&#xff09;——遗传算法详解与实现 0. 前言1. 遗传算法简介1.1 遗传学和减数分裂1.2 类比达尔文进化论 2. 遗传算法的基本流程2.1 创建初始种群2.2 计算适应度2.3 选择、交叉和变异2.4算法终止条件 3. 使用 Python 实现遗传算法3.1 构建种…...

Nginx+Tomcat实现负载均衡、动静分离集群部署

文章目录 一、Nginx​​实现负载均衡原理1.正向代理和反向代理2.负载均衡模式1. 轮询&#xff08;Round Robin&#xff09;&#xff1a;2. 最少连接数&#xff08;Least Connections&#xff09;&#xff1a;3. IP 哈希&#xff08;IP Hash&#xff09;&#xff1a;4. 加权轮询…...

英语学习8月19日

词根前缀后缀 accomplishment 成就 acid n.酸的&#xff0c;adj.酸的 acidity n.酸性 ace adj.顶尖的 acute adj.敏锐的&#xff1b;急性的&#xff1b;严重的 acuity n.敏锐 obtuse adj.迟钝的&#xff1b;钝角的 acuity n.敏锐&#xff0c;严重 1.前缀ac: 尖&#x…...

关于windows环境使用nginx的一些性能问题

遇到的问题 最近在一个windows环境中部署nginx&#xff0c;遇到了以下问题&#xff1a; 1. nginx启动了九个线程&#xff08;1master8woekr&#xff09;&#xff0c;但是所有链接都被1个woker接收&#xff0c;其余worker不工作 2. 用户端访问web很慢&#xff0c;登录服务器使…...

“解决Windows电脑无法投影到其他屏幕的问题:尝试更新驱动程序或更换视频卡“

背景: 今天在日常的工作中&#xff0c; 我想将笔记本分屏到另一个显示屏&#xff0c;我这电脑Windows10&#xff0c;当我按下Windows键P键&#xff0c;提示我"你的电脑不能投影到其他屏幕&#xff0c;请尝试从新安装驱动程序或使用"遇到这种问题。 解决方法1: 1.快…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)

宇树机器人多姿态起立控制强化学习框架论文解析 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架&#xff08;一&#xff09; 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

技术栈RabbitMq的介绍和使用

目录 1. 什么是消息队列&#xff1f;2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...

Golang——9、反射和文件操作

反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一&#xff1a;使用Read()读取文件2.3、方式二&#xff1a;bufio读取文件2.4、方式三&#xff1a;os.ReadFile读取2.5、写…...

华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)

题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...

Python网页自动化Selenium中文文档

1. 安装 1.1. 安装 Selenium Python bindings 提供了一个简单的API&#xff0c;让你使用Selenium WebDriver来编写功能/校验测试。 通过Selenium Python的API&#xff0c;你可以非常直观的使用Selenium WebDriver的所有功能。 Selenium Python bindings 使用非常简洁方便的A…...