Hdc命令

官网:HDC常见命令

全局option相关命令

Option 说明
-t [key] [command] 指定连接唯一标识的目标设备。标识可通过命令hdc list targets查询。
help/-h 打印hdc帮助信息。
version/-v 打印hdc版本信息。
-l [level] 指定运行时日志等级,默认为LOG_INFO。
checkserver 获取client-server版本。
  1. 显示hdc相关的帮助信息,命令格式如下:
    1
    hdc -h

返回值:

返回值 说明
HarmonyOS device connector(HDC) …

———————————global commands:—————————

-h/help [verbose] - Print hdc help, ‘verbose’ for more other cmds

…(此处省略详细帮助信息)
hdc命令使用帮助信息

使用方法:

1
hdc -h
  1. 显示hdc的版本信息,命令格式如下:
    1
    hdc -v

返回值:

返回值 说明
Ver: X.X.Xa hdc(SDK)的版本信息

使用方法:

1
hdc -v
  1. 连接设备时,若仅有一台,无需指定设备标识;若有多台,一次仅能连接一台,每次连接时需要指定连接设备的标识,命令格式如下:
    1
    hdc -t [key] [command]
    参数:
参数名 说明
key IP地址或USB序列号。
command hdc支持的命令。

返回值:

返回值 说明
命令执行返回内容 请参考对应命令的返回值
[Fail]Not match target founded, check connect-key please 连接的设备不存在
[Fail]ExecuteCommand need connect-key? 连接的设备不存在或同时连接多台设备时,未指定连接设备标识
Unknown operation command… 不支持的命令

使用方法

该方法需要与具体的操作命令搭配使用,下面以shell命令举例:

1
2
hdc list targets  // 获取设备信息
hdc -t [key] shell // -t后面添加的key需要替换为查询到的某一个设备信息,此处COMMAND命令为shell即进入调试命令行

[!说明]
一台用于开发的电脑可连接多个设备,每个设备有唯一的标识。如果通过网络连接设备,标识为IP地址;如果通过usb连接,标识为USB序列号。该命令需要跟随具体的操作命令。

  1. 指定运行时日志等级,默认为LOG_INFO,命令格式如下:
    1
    hdc -l [level] [command]
    参数:
参数 说明
[level] 指定运行时日志等级

0:LOG_OFF

1:LOG_FATAL

2:LOG_WARN

3:LOG_INFO

4:LOG_DEBUG

5:LOG_ALL
command hdc支持的命令

返回值:

返回值 说明
命令执行返回内容 请参考对应命令的返回值
LOG日志信息 对应指定的运行时等级日志打印

使用方法:

1
hdc -l 5 shell ls
  1. 获取client-server版本,命令格式如下:
    1
    hdc checkserver
    返回值:
返回值 说明
Client version: Ver: X.X.Xa, server version: Ver: X.X.Xa client-server版本号

使用方法:

1
hdc checkserver

查询设备列表相关命令

命令 说明
list targets [-v] 查询已连接的所有目标设备,添加-v选项,则会打印设备详细信息。

显示所有已连接的设备列表,命令格式如下:

1
hdc list targets[-v]

返回值:

返回值 说明
设备信息 已连接的设备列表信息
[Empty] 没有查询到设备信息

使用方法:

1
2
hdc list targets
hdc list targets -v

服务进程相关命令

命令 说明
target mount 读写模式挂载系统分区。(user不可用)
target boot 重启目标设备,查看目标列表可用list targets命令。
smode [-r] 授予设备端hdc后台服务进程root权限, 使用-r参数取消授权。(user不可用)
kill [-r] 终止hdc服务进程,使用-r参数触发服务进程重新启动。
start [-r] 启动hdc服务进程,使用-r参数触发服务进程重新启动。
  1. 以读写模式挂载系统分区,命令格式如下:
    1
    hdc target mount

返回值:

返回值 说明
Mount finish 挂载成功
[Fail]具体失败信息 挂载失败

使用方法:

1
hdc target mount
  1. 授予设备端hdc后台服务进程root权限,命令格式如下:
    1
    hdc smode [-r]

返回值:

返回值 说明
无返回值 授予权限成功
[Fail]具体失败信息 授予权限失败

使用方法:

1
2
hdc smode  
hdc smode -r // 取消root权限
  1. 终止hdc服务进程,命令格式如下:
    1
    hdc kill [-r]

返回值:

返回值 说明
Kill server finish 服务进程终止成功
[Fail]具体失败信息 服务进程终止失败

使用方法:

1
2
hdc kill
hdc kill -r // 重启并终止服务进程
  1. 启动hdc服务进程,命令格式如下:
    1
    hdc start [-r]
    返回值:
返回值 说明
无返回值 服务进程启动成功
[Fail]具体失败信息 服务进程启动失败

使用方法:

1
2
hdc start
hdc start -r // 服务进程启动状态下,触发服务进程重新启动

网络相关命令

命令 说明
fport ls 列出全部转发端口转发任务。
fport local remote 设置正向端口转发任务:监听“主机端口”,接收请求并进行转发, 转发到“设备端口”。
fport rm local__remote 删除正向端口转发任务:取消指定的“主机端口”转发。
rport remote local 设置反向端口转发任务:监听“设备端口”,接收请求并进行转发,转发到“主机端口”。
rport rm remote local 删除反向端口转发任务:取消指定的“设备端口”转发。
tmode usb 已连接设备切换为USB连接方式:设备端daemon进程重启,并首先选用USB连接方式。
tmode port [port-number] 已连接设备切换为网络连接方式:设备端daemon进程重启,并优先使用网络方式连接设备,如果连接设备失败,再选择USB连接。
tconn_ host_[:port] [-remove] 指定连接设备:通过“IP地址:端口号”来指定连接的设备,使用-remove参数断开连接。
  1. 列出全部转发端口转发任务,命令格式如下:
    1
    hdc fport ls
    返回值:
返回值 说明
‘tcp:1234 tcp:1080’ [Forward] 正向端口转发任务。
‘tcp:2080 tcp:2345’ [Reverse] 反向端口转发任务。
[empty] 无端口转发任务。

使用方法:

1
hdc fport ls
  1. 设置正向端口转发任务,执行后将设置指定的“主机端口”转发数据到“设备端口”转发任务,命令格式如下:
    1
    hdc fport local remote
    返回值:
返回值 说明
Forwardport result:OK 端口转发任务设置正常。
[Fail]Incorrect forward command 端口转发任务设置失败,端口转发参数错误。
[Fail]TCP Port listen failed at XXXX 端口转发任务设置失败,本地转发端口被占用。

使用方法:

1
hdc fport tcp:1234 tcp:1080
  1. 删除正向端口转发任务,执行后将指定的“主机端口”转发数据到“设备端口”转发任务删除,命令格式如下:
    1
    hdc fport rm localremote
    返回值:
返回值 说明
Remove forward ruler success, ruler:tcp:XXXX tcp:XXXX 端口转发任务删除正常。
[Fail]Remove forward ruler failed, ruler is not exist tcp:XXXX tcp:XXXX 端口转发任务删除失败,不存在指定的转发任务。

使用方法:

1
hdc fport rm tcp:1234 tcp:1080
  1. 设置反向端口转发任务,执行后将设置指定的“设备端口”转发数据到“主机端口”转发任务,命令格式如下:
    1
    hdc rport remote local
    返回值:
返回值 说明
Forwardport result:OK 端口转发任务设置正常。
[Fail]Incorrect forward command 端口转发任务设置失败,端口转发参数错误。
[Fail]TCP Port listen failed at XXXX 端口转发任务设置失败,本地转发端口被占用。

使用方法:

1
hdc rport tcp:1234 tcp:1080
  1. 删除反向端口转发任务,执行后将指定的“设备端口”转发数据到“主机端口”任务删除,命令格式如下:
    1
    hdc rport rm remote local
    返回值:
返回值 说明
Remove forward ruler success, ruler:tcp:XXXX tcp:XXXX 端口转发任务删除正常。
[Fail]Remove forward ruler failed, ruler is not exist tcp:XXXX tcp:XXXX 端口转发任务删除失败,不存在对应的转发任务。

使用方法:

1
hdc rport rm tcp:1234 tcp:1080
  1. 已连接设备切换为USB连接方式,命令格式如下:
    1
    hdc tmode usb
    返回值:
返回值 说明
切换成功。
[Fail]ExecuteCommand need connect-key 设备列表无网络连接方式设备,无法指定设备切换连接方式。

使用方法:

1
hdc tmode usb
  1. 已连接设备切换为网络连接方式,命令格式如下:
    1
    hdc tmode port [port-number]
    参数:
参数 参数说明
port-number 监听连接的网络端口号,范围:1~65536。

返回值:

返回值 说明
切换成功。
[Fail]ExecuteCommand need connect-key 切换失败,设备列表无设备,无法指定设备切换连接方式。
[Fail]Incorrect port range 端口号超出可设置范围(1~65536)。

使用方法:

1
hdc tmode port 1234

[!注意]
切换前,请确保条件满足:远端设备与近端执行机处于同一网络,且执行机可ping通远端设备IP。
如不满足以上条件请勿使用该命令进行切换。

[!说明]
执行完毕后,远端daemon将会退出并重启,USB连接将会断开,默认启用TCP连接,且仅可通过TCP进行连接,如需恢复USB连接有以下两种方法:
(1)执行hdc tconn [ip]:[port]命令进行TCP连接后,执行hdc tmode usb恢复。
(2)通过恢复出厂设置恢复。

  1. 指定连接的设备,命令格式如下:
    1
    hdc tconn host[:port] [-remove]
    参数:
参数 参数说明
host[:port] 设备IP地址与端口号,格式按照“IP地址:端口号“。
-remove 【可选】断开指定设备的连接。

返回值:

返回值 说明
Connect OK 连接成功。
[Info]Target is connected, repeat opration 设备当前已连接。
[Fail]Connect failed 连接失败。

使用方法:

1
2
hdc tconn 192.168.0.1:8888
hdc tconn 192.168.0.1:8888 -remove // 断开指定网络设备连接

文件相关命令

命令 说明
file send local remote 从本地发送文件至远端设备。
file recv remote local 从远端设备发送文件至本地。
  1. 从本地发送文件至远端设备,命令格式如下:
    1
    hdc file send local remote
    参数:
参数名 说明
local 本地待发送的文件路径。
remote 远程待接收的文件路径。

返回值:

文件发送成功,返回传输成功的结果信息。文件发送失败,返回传输失败的具体信息。

使用方法:

1
hdc file send E:\example.txt /data/local/tmp/example.txt
  1. 从远端设备发送文件至本地,命令格式如下:
    1
    hdc file recv remote local
    参数:
参数名 说明
local 本地待接收的文件路径。
remote 远程待发送的文件路径。

返回值:

文件接收成功,返回传输成功的结果信息。文件接收失败,返回传输失败的具体信息。

使用方法:

1
hdc file recv  /data/local/tmp/a.txt   ./a.txt

应用相关命令

命令 说明
install [-r/-g] packageFile 安装指定的应用package文件。
uninstall_ packageName_ 卸载指定的应用包package包名。
  1. 安装APP package,命令格式如下:
    1
    hdc install [-r/-g] packageFile
    参数:
参数名 说明
packageFile 应用安装包文件名。
-r 替换已存在应用。
-g 应用动态授权。

返回值:

返回值 说明
成功情况下无返回值。
具体安装失败原因 失败情况下返回具体安装失败信息。

使用方法:

以安装com.example.hello包为例:

1
hdc install E:\com.example.hello.hap
  1. 卸载应用,命令格式如下:
    1
    hdc uninstall [-k] packageName
    参数:
参数名 说明
packageName 应用安装包。
-k 保留/data/cache。

返回值:

返回值 说明
成功情况下无返回值。
具体卸载失败原因 失败情况下返回具体卸载失败信息。

使用方法:

以卸载com.example.hello包为例:

1
hdc uninstall com.example.hello

调试相关命令

命令 说明
jpid 显示可调试应用列表。
hilog [options] 打印设备端的日志信息,options表示hilog支持的参数,可通过hdc hilog -h查阅支持的参数列表 。
shell [COMMAND] 交互命令,COMMAND表示需要执行的单次命令。不同类型或版本的系统支持的COMMAND命令有所差异,可以通过hdc shell ls /system/bin查阅支持的命令列表。
  1. 抓取log信息,命令格式如下:
    1
    hdc hilog[options]
    参数:
参数 说明
[options] hilog支持的参数,可通过hdc hilog -h查阅支持的参数列表。

返回值:

返回值 说明
返回具体信息 抓取的日志信息。

使用方法:

1
2
hdc hilog 
hdc shell "hilog -r" // 清理hilog缓存日志
  1. 显示可调试应用列表,命令格式如下:
    1
    hdc jpid
    返回值:
返回值 说明
应用名列表 可调试应用名列表。
[empty] 无可调式应用。

使用方法:

1
hdc jpid
  1. 交互命令,命令格式如下:
    1
    hdc shell [COMMAND]
    参数:
参数 说明
[COMMAND] 调试命令行可用命令,详细可用命令help来获取全部命令提示。

返回值:

返回值 说明
交互命令返回内容 返回内容详情请参见其他交互命令返回内容。
/bin/sh: XXX : inaccessible or not found 不支持的交互命令。

使用方法:

1
2
hdc shell ps -ef  
hdc shell help -a // 查询全部可用命令

鸿蒙HDC命令合集

测试之家:鸿蒙社区

HDC 安装

  • 通过访问社区网站(http://ci.openharmony.cn/workbench/cicd/dailybuild/dailylist)下载 ohos-sdk-public 或正式发布的 sdk 压缩包
  • 配置电脑环境变量, 以 macOS 为例,在~/.bash_profile 或者 ~/.zshrc文件中添加如下内容:
    1
    2
    export PATH=$PATH:/Users/Huawei/Sdk/hmscore/4.2.1/toolchains        //请以sdk实际安装目录为准 
    export HDC_SERVER_PORT=7035
    也可以自行编译安装:参考鸿蒙官方 gitree 文档

    基本语法

    1
    hdc -t <connectKey> <command>
    如果只有一个设备/模拟器连接时,可以省略掉-t <connectKey> 这一部分,直接使用hdc <command>。在多个设备/模拟器连接的情况下需要指定-t 参数, connectKey可以通过hdc list targets命令获取,对应 Android 里的adb devices获取的serialNumber
    1
    $ hdc list targets
    注意事项
  • 使用hdc,如果出现异常,可以尝试通过hdc kill -r命令杀掉并重启 hdc 服务。
  • 如果出现hdc list targets获取不到设备信息的情况,可以通过任务管理器查看是否有 hdc 进程存在。若进程存在,则通过hdc kill -r命令杀掉该进程

    设备连接管理

    查看版本

    1
    $ hdc -v

    启动/停止 HDC Server

    停止
    1
    $ hdc kill
    重启
    1
    $ hdc start -r

    查询设备列表

    1
    $ hdc list targets
    -v 选项 显示详细信息
    1
    2
    3
    4
    $ hdc list targets -v

    127.0.0.1:5555 TCP Connected localhost
    FMR0223C13000649 USB Connected unknown...
    输出的内容第一列为设备的connectKey, 第二列是设备连接方式,第三列为设备连接状态,第四列暂时未知

    查询设备 UDID

    1
    2
    3
    4
    $ hdc shell bm get --udid

    udid of current device is :
    C46284C052AE01BBD2358FE44B279524B508FC959AAB5F4B0B74E42A06569B7E
    这个udid在用开发者账号打包时,需要添加这个udid到对应的profile文件中

    重启手机

    1
    $ hdc target boot

应用管理

安装应用

1
2
3
4
$ hdc app install entry-default-signed.hap

[Info]App install path:/Users/develop/entry-default-signed.hap, queuesize:0, msg:install bundle successfully.
AppMod finish

或者

1
2
3
4
$ hdc install entry-default-signed.hap

[Info]App install path:/Users/develop/entry-default-signed.hap, queuesize:0, msg:install bundle successfully.
AppMod finish

卸载应用

1
2
3
4
$ hdc app uninstall com.kk.hmscrcpy

[Info]App uninstall path:, queuesize:0, msg:uninstall bundle successfully.
AppMod finish

或者

1
2
3
4
$ hdc uninstall com.kk.hmscrcpy

[Info]App uninstall path:, queuesize:0, msg:uninstall bundle successfully.
AppMod finish

获取应用列表

解释

1
$ hdc shell bm dump -a

启动应用

通过启动Ability来拉起APP

1
hdc shell aa start -a {abilityName} -b {bundleName} 
  • 其中bundleName可以通过hdc shell bm dump -a获取
  • 其中abilityName可以通过如下命令获取(查看当前任务栈的 ability 信息)
    解释
    1
    $ hdc shell aa dump -l # 运行命令前需要手动打开app

    退出应用

    强制退出应用
    1
    hdc shell aa force-stop {bundleName} 
  • 其中bundleName可以通过hdc shell bm dump -a获取

    获取应用版本

    1
    $ hdc shell bm dump -n {bundleName}
    执行上述命令后,再解析 json, 提取versionName字段即可

Dump 应用信息

aa dump

1
$ hdc shell aa dump -h

bm dump

1
$ hdc shell bm dump -h

获取应用 Ability 信息

1
$ hdc shell aa dump -l    //运行命令前需要手动打开app  

获取应用详情

查询该应用的详细信息

1
$ hdc shell bm dump -n com.kuaishou.hmapp

通过这个命令可以获取到很多应用的关键信息,比如reqPermissionsversionabilities等等

清除应用数据

1
$ hdc shell aa dump -l # 运行命令前需要手动打开app$ hdc shell bm clean -h

清除应用缓存

1
2
3
$ hdc shell bm clean -n {bundleName}  -c

clean bundle cache files successfully.

其中bundleName可以通过hdc shell bm dump -a获取, 比如com.kuaishou.hmapp

清除应用数据

1
$ hdc shell bm clean -n {bundleName} -d 

显示可调试应用列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ hdc jpid 
2571
2633
2638
2658
2666
2691
2825
3310
3804
3977
30178

$ hdc track-jpid
0000
  • jpid显示可调试应用列表
  • track-jpid动态显示可调试应用列表。

查看设备信息

名称

1
2
3
$ hdc shell param get const.product.name               

HUAWEI Mate 60 Pro

Brand

1
2
3
$ hdc shell param get const.product.brand

HUAWEI

Model

1
2
3
$ hdc shell param get const.product.model

ALN-AL00

系统版本

1
2
3
$ hdc shell param get const.product.software.version                                      

ALN-AL00 5.0.0.22(SP35DEVC00E22R4P1log)

OS 版本

1
2
3
$ hdc shell param get const.ohos.apiversion  

12

CPU 架构

1
2
3
$ hdc  shell param get const.product.cpu.abilist  

arm64-v8a

分辩率

1
2
3
4
5
6
7
8
9
10
11
12
13
$ hdc shell hidumper -s RenderService -a screen   

-------------------------------[ability]-------------------------------
----------------------------------RenderService---------------------------------
-- ScreenInfo
screen[0]: id=0, powerstatus=POWER_STATUS_OFF, backlight=51, screenType=EXTERNAL_TYPE, render size: 1260x2720, physical screen resolution: 1260x2720, isvirtual=false, skipFrameInterval_:1

supportedMode[0]: 1260x2720, refreshrate=120
supportedMode[1]: 1260x2720, refreshrate=90
supportedMode[2]: 1260x2720, refreshrate=60
supportedMode[3]: 1260x2720, refreshrate=30
activeMode: 1260x2720, refreshrate=60
capability: name=, phywidth=72, phyheight=156,supportlayers=12, virtualDispCount=0, propCount=0, type=DISP_INTF_HDMI, supportWriteBack=false

执行上述命令后,解析返回内容,可以通过正则表达式提取1260x2720

wlanip

1
$ hdc shell ip address show

电量/温度

1
$ hdc shell hidumper -s BatteryService -a -i                  

查看屏幕状态

可以通过如下命令判断屏幕是否点亮

1
$ hdc shell hidumper -s 3301 -a -a  

端口转发

命令 说明
fport ls 展示全部 “端口转发主机端口转发数据到设备侧端口” 的转发任务
fport local remote 端口转发主机端口转发数据到设备侧端口
fport rm local remote 删除指定 “端口转发主机端口转发数据到设备侧端口” 的转发任务
rport ls 展示全部 “端口转发设备侧端口转发数据到主机端口” 的转发任务
rport local remote 端口转发设备侧端口转发数据到主机端口
rport rm local remote 删除指定 “端口转发设备侧端口转发数据到主机端口” 的转发任务

显示端口转发列表

展示电脑端口转发到手机端口的列表

1
2
3
$ hdc fport ls

FMR0223C13000649 tcp:7912 tcp:7912 [Forward]

本地端口转发到手机

将本地电脑的7913端口转发到手机7912端口

1
2
3
$ hdc fport tcp:7913 tcp:7912

Forwardport result:OK

这个命令非常实用,比如我再手机上实现了一个 http服务,没有这个命令前需要通过手机ip:port来访问,这就需要提前知道手机的wlanIP,执行这个命令后可以直接通过localhost:localPort来访问手机里的服务。

删除端口转发任务

1
2
3
4
5
$ hdc fport rm tcp:7913 
tcp:7912 Remove forward ruler success, ruler:tcp:7913 tcp:7912

$ hdc fport ls
[Empty]

同理,rport命令表示手机端口转发到电脑端口,我就不一一举例了.

无线调试

  1. 在手机上开启 5555 端口 hdc -t {SERIAL} tmode port {PORT}
  2. 连接手机上的端口 hdc -t {SERIAL} tconn {WLANIP}:{PORT}
  3. 恢复手机 USB 连接 hdc -t {SERIAL} tmode usb

示例

1
2
3
4
5
6
7
8
9
10
$ hdc tmode port 5555  

$ hdc tconn 172.31.124.84:5555
Connect OK

$ hdc list targets
172.31.124.84:5555

$ hdc tmode usb
Set device run mode successful.

不过目前这个无线调试,会导致该手机 USB 连接方式断开,导致无法进行端口转发,每次进行无线调试时,需要知道手机的 wlanip 才行。
这个问题也在和鸿蒙方沟通,待解决。
记个 TODO.

文件传输

命令 说明
file send local remote 从本地发送文件至远端设备
file recv remote local 从远端设备发送文件至本地

从本地电脑发送文件至手机

1
2
3
$ hdc file send ~/layout_407568854.json /data/local/tmp/layout_407568854.json

FileTransfer finish, Size:71792, File count = 1, time:24ms rate:2991.33kB/s

从手机拷贝文件至本地电脑

1
2
3
4
$ hdc file recv /data/local/tmp/layout_407568854.json ~/layout_407568854.json

[I][2024-05-28 20:15:45] HdcFile::TransferSummary success
FileTransfer finish, Size:71792, File count = 1, time:12ms rate:5982.67kB/s

uitest 工具

1
$ hdc shell uitest help

UI 模拟操作

支持操作类型:点击 双击 长按 慢滑 快滑 拖拽 输入文字 KeyEvent

配置参数名 配置参数含义 配置参数取值 示例
click 模拟单击操作 point_x (必选参数,点击 x 坐标点)
point_y (必选参数,点击 y 坐标点)
hdc shell uitest uiInput click point_x point_y
doubleClick 模拟双击操作 point_x (必选参数,双击 x 坐标点)
point_y (必选参数,双击 y 坐标点)
hdc shell uitest uiInput doubleClick point_x point_y
longClick 模拟长按操作 point_x (必选参数,长按 x 坐标点)
point_y (必选参数,长按 y 坐标点)
hdc shell uitest uiInput longClick point_x point_y
fling 模拟快滑操作 from_x (必选参数,滑动起点 x 坐标)
from_y(必选参数,滑动起点 y 坐标)
to_x(必选参数,滑动终点 x 坐标)
to_y(必选参数,滑动终点 y 坐标)
swipeVelocityPps_ (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600, 单位: px/s)
stepLength(可选参数,滑动步长,默认值:滑动距离/50, 单位: px)
hdc shell uitest uiInput fling from_x from_y to_x to_y swipeVelocityPps_ stepLength
swipe 模拟慢滑操作 from_x (必选参数,滑动起点 x 坐标)
from_y(必选参数,滑动起点 y 坐标)
to_x(必选参数,滑动终点 x 坐标)
to_y(必选参数,滑动终点 y 坐标)
swipeVelocityPps_ (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600, 单位: px/s)
hdc shell uitest uiInput swipe from_x from_y to_x to_y swipeVelocityPps_
drag 模拟拖拽操作 from_x (必选参数,拖拽起点 x 坐标)
from_y(必选参数,拖拽起点 y 坐标)
to_x(必选参数,拖拽终点 x 坐标)
to_y(必选参数,拖拽终点 y 坐标)
swipeVelocityPps_ (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600, 单位: px/s)
hdc shell uitest uiInput drag from_x from_y to_x to_y swipeVelocityPps_
dircFling 模拟指定方向滑动操作 direction (可选参数,滑动方向,可选值: [0,1,2,3], 滑动方向: [左,右,上,下],默认值: 0)
swipeVelocityPps_ (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600, 单位: px/s)
stepLength(可选参数,滑动步长,默认值:滑动距离/50, 单位: px)
hdc shell uitest uiInput dircFling direction swipeVelocityPps_ stepLength
inputText 模拟输入框输入文本操作 point_x (必选参数,输入框 x 坐标点)
point_y (必选参数,输入框 y 坐标点)
input(输入文本)
hdc shell uitest uiInput inputText point_x point_y text
keyEvent 模拟实体按键事件 (如:键盘,电源键,返回上一级,返回桌面等),以及组合按键操作 keyID (必选参数,实体按键对应 ID)
keyID2 (可选参数,实体按键对应 ID)
hdc shell uitest uiInput keyEvent keyID

举例

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
//点击 
hdc shell uitest uiInput click 100 100

//双击
hdc shell uitest uiInput doubleClick 100 100

//长按
hdc shell uitest uiInput longClick 100 100

//快滑
hdc shell uitest uiInput fling 10 10 200 200 500

//慢滑
hdc shell uitest uiInput swipe 10 10 200 200 500

//拖拽
hdc shell uitest uiInput drag 10 10 100 100 500

//左滑
hdc shell uitest uiInput dircFling 0 500

//右滑
hdc shell uitest uiInput dircFling 1 600

//上滑
hdc shell uitest uiInput dircFling 2

//下滑
hdc shell uitest uiInput dircFling 3

//输入框输入
hdc shell uitest uiInput inputText 100 100 hello

//返回主页
hdc shell uitest uiInput keyEvent Home

//返回上一步
hdc shell uitest uiInput keyEvent Back

//组合键粘贴操作
hdc shell uitest uiInput keyEvent 2072 2038

keyEvent映射表可以参考这个文档:https://docs.openharmony.cn/pages/v4.1/en/application-dev/reference/apis-input-kit/js-apis-keycode.md

获取页面布局信息(控件树)

1
2
3
$ hdc shell uitest dumpLayout -p {saveDumpPath}   # 运行命令前需要手动打开app,进入对应页面

DumpLayout saved to:/data/local/tmp/layout_407568854.json
  • -p表示控件树保存的目录,如果不指定,则默认保存在手机的/data/local/tmp目录
    /data/local/tmp/layout_407568854.json文件内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{ 
"attributes": {
"accessibilityId": "",
"bounds": "[0,0][1260,2720]",
"checkable": "",
"checked": "",
"clickable": "",
"description": "",
"enabled": "",
"focused": "",
"hostWindowId": "",
"id": "",
"key": "",
"longClickable": "",
"origBounds": "",
"scrollable": "",
"selected": "",
"text": "",
"type": ""
},
"children": [ ... ]

录制用户操作

将当前界面操作记录到/data/local/tmp/layout/record.csv,结束录制操作使用Ctrl+C结束录制

1
$  hdc shell uitest uiRecord record  

支持两种方式查看数据:

  • uiRecord record, 将事件的位置坐标写入文件
  • uiRecord read, 将文件内容打印到控制台
    录制完成后,再将csv文件拷贝到电脑上
    1
    $ hdc file recv  /data/local/tmp/layout/record.csv ~/record.csv
    record数据字段含义请参考如下示例数据
    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
    {   
    "ABILITY": "com.ohos.launcher.MainAbility", // 前台应用界面
    "BUNDLE": "com.ohos.launcher", // 操作应用
    "CENTER_X": "", // 模拟捏合中心X, pinch事件
    "CENTER_Y": "", // 模拟捏合中心Y, pinch事件
    "EVENT_TYPE": "pointer", //
    "LENGTH": "0", // 总体步长
    "OP_TYPE": "click", //事件类型,当前支持点击、双击、长按、拖拽、捏合、滑动、抛滑动作录制
    "VELO": "0.000000", // 离手速度
    "direction.X": "0.000000",// 总体移动X方向
    "direction.Y": "0.000000", // 总体移动Y方向
    "duration": 33885000.0, // 手势操作持续时间
    "fingerList": [{
    "LENGTH": "0", // 总体步长
    "MAX_VEL": "40000", // 最大速度
    "VELO": "0.000000", // 离手速度
    "W1_BOUNDS": "{"bottom":361,"left":37,"right":118,"top":280}", // 起点控件bounds
    "W1_HIER": "ROOT,3,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0", // 起点控件hierarchy
    "W1_ID": "", // 起点控件id
    "W1_Text": "", // 起点控件text
    "W1_Type": "Image", // 起点控件类型
    "W2_BOUNDS": "{"bottom":361,"left":37,"right":118,"top":280}", // 终点控件bounds
    "W2_HIER": "ROOT,3,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0", // 终点控件hierarchy
    "W2_ID": "", // 终点控件id
    "W2_Text": "", // 终点控件text
    "W2_Type": "Image", // 终点控件类型
    "X2_POSI": "47", // 终点X
    "X_POSI": "47", // 起点X
    "Y2_POSI": "301", // 终点Y
    "Y_POSI": "301", // 起点Y
    "direction.X": "0.000000", // x方向移动量
    "direction.Y": "0.000000" // Y方向移动量
    }],
    "fingerNumber": "1" //手指数量
    }

屏幕截图

hdc 提供了两种截图命令
方式一

1
2
3
4
5
$ hdc shell uitest screenCap 
// 默认存储路径:/data/local/tmp,文件名:时间戳 + .png。

$ hdc shell uitest screenCap -p /data/local/1.png
// 指定存储路径和文件名。

【推荐】方式二

1
2
$ hdc shell snapshot_display -f /data/local/2.png
// 截图完成后可以通过 hdc file recv 命令导入到本地

方式二的截图性能效率远远高于方式一

屏幕录屏

hdc 命令还未支持,官方在开发中。。。

收起键盘

1
$ hdc shell uinput -K -d 2 -i 2 -u 2

hidumper 工具

1
$ hdc shell hidumper -h

system abilities

1
$ hdc shell hidumper -ls  

获取到 abilities 后,就可以指定 service 获取相关的信息。 比如通过 RenderService 获取一些信息

1
$ hdc shell hidumper -s RenderService

获取分辩率

1
$ hdc shell hidumper -s RenderService -a screen

获取帧率
首先执行如下命令进入到 shell 环境

1
$ hdc shell

然后执行hidumper [surface name] fps , 例如composer fps

1
$ hidumper -s RenderService -a "composer fps" 

aa 工具

Ability assistant(Ability 助手,简称为 aa),是实现应用及测试用例启动功能的工具,为开发者提供基本的应用调试和测试能力,例如启动应用组件、强制停止进程、打印应用组件相关信息等。

1
$ hdc shell aa help 

start

stop-service

force-stop

test

attach

detach

appdebug

详细介绍请参考文档:https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/tools/aa-tool.md

bm 工具

Bundle Manager(包管理工具,简称 bm)是实现应用安装、卸载、更新、查询等功能的工具,bm 为开发者提供基本的应用安装包的调试能力,例如:安装应用,卸载应用,查询安装包信息等。

1
$ hdc shell bm help 

install

uninstall

dump

clean

enable

disable

get

详细介绍请参考文档:https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/tools/bm-tool.md

param 工具

param 是为开发人员提供用于操作系统参数的工具,该工具只支持标准系统。

1
$ hdc shell param 

详细介绍请参考文档:https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/tools/param-tool.md

设备日志

1
$ hdc hilog -h  

Instrument Test

主要用来做 APP 的 UI 自动化测试,将应用测试包安装到测试设备上,在 cmd 窗口中执行 aa 命令,完成对用例测试。

aa test命令执行配置参数

执行参数全写 执行参数缩写 执行参数含义 执行参数示例
–bundleName -b 应用 Bundle 名称 -b com.test.example
–packageName -p 应用模块名,适用于 FA 模型应用 -p com.test.example.entry
–moduleName -m 应用模块名,适用于 STAGE 模型应用 -m entry
NA -s 特定参数,以 键值对方式传入 -s unittest /ets/testrunner/OpenHarmonyTestRunner
1
$ hdc shell aa test -h 

举例

1
$ hdc shell aa test -b com.example.myapplication -m entry_test -s unittest /ets/testrunner/OpenHarmonyTestRunner -s class UiTestDemo timeout 15000

查看测试结果
cmd 模式执行过程,会打印如下相关日志信息。

性能工具

SmartPerf是一款基于系统开发的性能功耗测试工具,操作简单易用。工具可以检测性能、功耗相关指标,包括FPSCPUGPURAMTemp等,通过量化的指标项了解应用性能状况。在开发过程中,使用的可能是有屏或无屏设备,对此SmartPerf提供了两种方式:分别是SmartPerf-DeviceSmartPerf-DaemonSmartPerf-Device适用于有屏设备,支持可视化操作。测试时是通过悬浮窗的开始和暂停来实时展示性能指标数据,保存后可生成数据报告,在报告中可分析各指标数据详情。SmartPerf-Daemon支持shell命令行方式,同时适用于有屏和无屏设备。

  • CPU:每秒读取一次设备节点下 CPU 大中小核的频点和各核使用率,衡量应用占用 CPU 资源的情况,占用过多的 CPU 资源会导致芯片发烫。
  • GPU:每秒读取一次设备节点下 GPU 的频点和负载信息,衡量应用占用 GPU 资源的情况,当 GPU 占用过多时,会导致性能下降,应用程序的运行速度变慢。
  • FPS:应用界面每秒刷新次数,衡量应用画面的流畅度,FPS 越高表示图像流畅度越好,用户体验也越好。
  • POWER:每秒读取一次设备节点下的电流及电压信息。
  • TEMP:每秒读取一次设备节点下电池温度、系统芯片温度等信息。
  • RAM:每秒读取一次应用进程的实际物理内存,衡量应用的内存占比情况。
  • snapshot:每秒截取一张应用界面截图。
1
2
3
4
5
6
7
8
$ hdc shell  

# SP_daemon

// 查看daemon进程是否存在
# ps -ef | grep SP_daemon
root 1584 1 0 21:50:05 ? 00:00:00 SP_daemon
root 1595 1574 3 21:51:02 pts/0 00:00:00 grep SP_daemon

执行查看帮助命令

1
# SP_daemon --help 

基于hdc命令行的SmartPerf性能工具使用详细文档参考这个:https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/application-test/smartperf-guidelines.md

实例

HarmonyOS - HDC命令与ADB命令使用对比

HDC与ADB常用命令对比

HDC ADB 说明
hdc -h adb –help 查看帮助
hdc -v adb –version 查看版本
hdc list targets adb devices 查看连接设备
hdc kill adb kill-server 结束服务
hdc kill -r adb start-server 启动服务
hdc app install [安装包路径] adb install [安装包路径] 安装应用
hdc app uninstall package adb uninstall package 卸载应用
hdc hilog adb logcat 抓取log
hdc shell hilogcat >log.log adb shell logcat >log.log 抓取log并保存
hdc shell reboot adb reboot 重启设备
hdc shell bm get -u adb shell bm get -u 获取UUID
hdc file recv REMOTE… LOCAL adb pull REMOTE… LOCAL 接收文件
REMOTE:手机
LOCAL:PC
hdc file send LOCAL… REMOTE adb push LOCAL… REMOTE 发送文件
hdc shell screencap filename adb shell screencap filename 截屏
hdc shell screenrecord filename adb shell screenrecord filename 录屏

获取UUID

1
hdc shell bm get -u > uuid.log

获取hilog日志

1
hdc hilog

抓取log并保存

1
hdc shell hilogcat >log.log

获取当前页面信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@echo off &color 02 &PUSHD %~DP0 &TITLE 获取当前鸿蒙页面
::设置窗口大小
mode con lines=30 cols=100

:menu
cls

::hdc wait-for-device
echo "当前鸿蒙页面"
hdc shell aa dump -l
echo.
echo.

echo. & pause
goto menu

启动应用

1
2
3
4
5
6
7
8
::获取bundleName
hdc shell bm dump -a

::获取abilityName【需要先手动打开app】
hdc shell aa dump -l

::启动应用
hdc shell aa start -a {abilityName} -b {bundleName}

命令行安装app的脚本install.sh

使用 DevEco Studio 创建一个工程,然后一个 basic的hsp 和 login的har,让entry依赖这两个mudule,运行,看看执行了哪些命令:

1
2
3
4
5
6
7
8
9
10
build task in 1 s 364 ms
Launching com.nzy.installapp
$ hdc shell aa force-stop com.nzy.installapp
$ hdc shell mkdir data/local/tmp/5588cff7d2344a0db70a270bb22aa455
$ hdc file send /Users/xxx/DevEcoStudioProjects/InstallApp/feature/login/build/default/outputs/default/login-default-signed.hsp "data/local/tmp/5588cff7d2344a0db70a270bb22aa455" in 54 ms
$ hdc file send /Users/xxx/DevEcoStudioProjects/InstallApp/entry/build/default/outputs/default/entry-default-signed.hap "data/local/tmp/5588cff7d2344a0db70a270bb22aa455" in 34 ms
$ hdc shell bm install -p data/local/tmp/5588cff7d2344a0db70a270bb22aa455 in 217 ms
$ hdc shell rm -rf data/local/tmp/5588cff7d2344a0db70a270bb22aa455
$ hdc shell aa start -a EntryAbility -b com.nzy.installapp in 148 ms
Launch com.nzy.installapp success in 1 s 145 ms
1
2
3
4
5
6
hdc shell aa force-stop hmos.com.xm597.app
hdc shell mkdir data/local/tmp/5588cff7d2344a0db70a270bb22aa455
hdc file send D:/code/Company/HarmonyOS597/products/zhipin/build/release/outputs/release/zhipin-release-signed.hap "data/local/tmp/5588cff7d2344a0db70a270bb22aa455"
hdc shell bm install -p data/local/tmp/5588cff7d2344a0db70a270bb22aa455
hdc shell rm -rf data/local/tmp/5588cff7d2344a0db70a270bb22aa455
hdc shell aa start -a ZhipinAbility -b hmos.com.xm597.app

替换其中的bundleNameentryAbility的值
执行 ./install.sh [包的路径]

fold
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#!/bin/bash
#11/15 10:58:55:619: Launching com.nzy.installapp
#11/15 10:58:55:620: $ hdc shell aa force-stop com.nzy.installapp
#11/15 10:58:55:791: $ hdc shell mkdir data/local/tmp/c3af89b189d2480395ce746621ce6385
#11/15 10:58:55:852: $ hdc file send /Users/xxx/DevEcoStudioProjects/InstallApp/feature/login/build/default/outputs/default/login-default-unsigned.hsp "data/local/tmp/c3af89b189d2480395ce746621ce6385" in 61 ms
#11/15 10:58:55:882: $ hdc file send /Users/xxx.nie/DevEcoStudioProjects/InstallApp/entry/build/default/outputs/default/entry-default-unsigned.hap "data/local/tmp/c3af89b189d2480395ce746621ce6385" in 30 ms
#11/15 10:58:56:103: $ hdc shell bm install -p data/local/tmp/c3af89b189d2480395ce746621ce6385 in 220 ms
#11/15 10:58:56:153: $ hdc shell rm -rf data/local/tmp/c3af89b189d2480395ce746621ce6385
#11/15 10:58:56:410: $ hdc shell aa start -a EntryAbility -b com.nzy.installapp in 182 ms
#11/15 10:58:56:411: Launch com.nzy.installapp success in 791 ms
function printInfo() {
# ANSI 转义码颜色 绿色
local message=$1
printf "\e[32m%s\e[0m\n" "$message" # Info
}

function printError() {
# ANSI 转义码颜色 红色
local message=$1
printf "\e[31m%s\e[0m\n" "错误:$message"
# 退出程序
# exit 1
}

# 下载之后解压的文件夹 ,解压默认是和 install.sh 脚本在同一个目录
hdcZip="tools.zip"
hdcTool="tools"
# hdc文件路径"
hdcPath="tools/hdc"
#包名
bundleName="hmos.com.xm597.app"
# 要打开的Ability
entryAbility="ZhipinAbility"

checkAndDownloadHdc(){
if [ ! -f "${hdcPath}" ]; then
# 不存在开始下载
printInfo "首次需要下载hdc工具,2M"
URL="https://gitee.com/zhiyangnie/install-shell/raw/master/tools.zip"
# 下载到当前目录的 tools.zip
# 使用 curl 下载
curl -o "$hdcZip" "$URL"
if [ $? -eq 0 ]; then
printInfo "下载成功,准备解压${hdcZip}..."
# 解压ZIP文件
unzip -o "$hdcZip" -d "${hdcTool}"
# 检查解压是否成功
if [ $? -eq 0 ]; then
printInfo "${hdcZip}解压成功"
# 删除zip
rm "$hdcZip"
else
printError "${hdcZip} 解压失败,请手动解压"
fi
else
printError "下载失败,请检查网络"
fi
fi
}


# 判断是否已经下载过hdc文件
checkAndDownloadHdc

# 判断是否连接手机且仅有一个手机
devicesList=$(${hdcPath} list targets)

# 判断是否hdc 可用
if [ -z "$devicesList" ]; then
# 开始下载zip
print_error "hdc 不可用 ,请检查本目录是否存在 ${hdcPath}"
fi

# 判断是否连接手机,如果有 [Empty] 表明 一个手机也没连接
if [[ "$devicesList" == *"[Empty]"* ]]; then
printError "未识别到手机,请连接手机,打开开发者选项和USB调试"
fi


# 判断连接手机的个数
deviceCount=$(${hdcPath} list targets | wc -l)
if [ "$deviceCount" -ne 1 ]; then
printError "错误:连接的手机个数是 ${deviceCount} 个,请连接一个手机"
fi

printInfo "连接到手机,且仅有一个手机 ${devicesList}"



# 传过来的参数是 ,获取输入的 app 文件
appFile="$1"

# 判读传过来的路径文件是否以.app 结尾
if [[ ! "${appFile}" =~ .app ]]; then
printError "请传入正确的包路径,文件要 .app 结尾"
fi

# 判断文件是否存在
if [ ! -e "$appFile" ]; then
printError "不存在该文件 $appFile 。请确认"
fi

#------------------------------开始安装----------------------------------
# 开始安装
printInfo "开始安装应用, ${bundleName}"
# 1.先kill当前app的进程
$hdcPath shell aa force-stop "$bundleName"

# hdc shell mkdir data/local/tmp/c3af89b189d2480395ce746621ce6385
# 2.创建随机文件夹
randomHex=$(xxd -l 16 -p /dev/urandom)
randomFile="data/local/tmp/$randomHex"
mkDirSuccess=$($hdcPath shell mkdir "$randomFile" 2>&1)
if [ -n "$mkDirSuccess" ]; then
printError "手机中:随机创建文件夹 ${randomFile} 失败 , $mkDirSuccess"
else
printInfo "手机中:创建随机文件夹 ${randomFile} 成功"
fi
# 3.解压.app中
# 在本地创建 tmp 临时文件夹
tmp="tmp"
# 存在先删除
if [ -d "${tmp}" ]; then
rm -rf "$tmp"
fi
mkdir -p "$tmp"
# 解压.app ,使用 unUse 主要是 不想打印那么多的解压日志
unUse=$(unzip -o "$appFile" -d "$tmp")
if [ $? -eq 0 ]; then
printInfo "解压app成功"
else
printError "解压app失败,请传入正确的app。$appFile , "
fi


printInfo "遍历解压发送到 手机的$randomFile"
# 4.遍历 tmp 文件夹中的文件发送到 randomFile 中
for item in "${tmp}"/*; do
if [ -f "$item" ]; then
# 发送 以 .hsp 或 .hap 结尾。
if [[ "$item" == *.hsp || "$item" == *.hap ]]; then
$hdcPath file send "$item" "$randomFile"
fi
fi
done
printInfo "成功发送到 手机的$randomFile "

# 5. 使用 install
# hdc shell bm install -p data/local/tmp/c3af89b189d2480395ce746621ce6385

installStatus=$($hdcPath shell bm install -p "$randomFile" 2>&1)
if [[ "$installStatus" == *"successfully"* ]]; then
printInfo "┌────────────────────────────────────────────────────────"
printInfo "│ ? 安装成功 "
printInfo "└────────────────────────────────────────────────────────"
${hdcPath} shell aa start -a "${entryAbility}" -b "$bundleName"
else
printf "\e[31m%s\e[0m\n" "┌────────────────────────────────────────────────────────"
printf "\e[31m%s\e[0m\n" "│? 安装错误"
echo "$installStatus" | while IFS= read -r line; do
printf "\e[31m%s\e[0m\n" "│${line}"
done
printf "\e[31m%s\e[0m\n" "│错误码:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/bm-tool-V5"
printf "\e[31m%s\e[0m\n" "└────────────────────────────────────────────────────────"

fi

# 6. 删除 手机端的 $randomFile
${hdcPath} shell rm -rf "$randomFile"
# 删除本地的tmp文件夹
rm -rf "$tmp"


pause=1

function pause()
{
if [ "x$1" != "x" ]; then
echo $1
fi
if [ $enable_pause -eq 1 ]; then
echo "Press any key to continue!"
char=`get_char`
fi
}


# 如果执行 报着错误 zsh: permission denied: ./a.sh
# 执行,如果没有x 比如像这样 -rw-r--r--
# ls -l install.sh
# 加入x
# chmod +x install.sh

带手动签名gitee地址

fold
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#!/bin/bash
#11/15 10:58:55:619: Launching com.nzy.installapp
#11/15 10:58:55:620: $ hdc shell aa force-stop com.nzy.installapp
#11/15 10:58:55:791: $ hdc shell mkdir data/local/tmp/c3af89b189d2480395ce746621ce6385
#11/15 10:58:55:852: $ hdc file send /Users/xxx/DevEcoStudioProjects/InstallApp/feature/login/build/default/outputs/default/login-default-unsigned.hsp "data/local/tmp/c3af89b189d2480395ce746621ce6385" in 61 ms
#11/15 10:58:55:882: $ hdc file send /Users/xxx.nie/DevEcoStudioProjects/InstallApp/entry/build/default/outputs/default/entry-default-unsigned.hap "data/local/tmp/c3af89b189d2480395ce746621ce6385" in 30 ms
#11/15 10:58:56:103: $ hdc shell bm install -p data/local/tmp/c3af89b189d2480395ce746621ce6385 in 220 ms
#11/15 10:58:56:153: $ hdc shell rm -rf data/local/tmp/c3af89b189d2480395ce746621ce6385
#11/15 10:58:56:410: $ hdc shell aa start -a EntryAbility -b com.nzy.installapp in 182 ms
#11/15 10:58:56:411: Launch com.nzy.installapp success in 791 ms
function printInfo() {
# ANSI 转义码颜色 绿色
local message=$1
printf "\e[32m%s\e[0m\n" "$message" # Info
}
function printDebug() {
# ANSI 转义码颜色 绿色
local message=$1
printf "\e[36m%s\e[0m\n" "$message" # Info
}

function printError() {
# ANSI 转义码颜色 红色
local message=$1
printf "\e[31m%s\e[0m\n" "错误:$message"
# 退出程序
exit 1
}

# 下载之后解压的文件夹 ,解压默认是和 install.sh 脚本在同一个目录
hdcZip="tools.zip"
hdcTool="tools"
# hdc文件路径"
hdcPath="tools/hdc"
#包名
bundleName="com.nzy.installapp"
# 要打开的Ability
entryAbility="EntryAbility"

checkAndDownloadHdc(){
if [ ! -f "${hdcPath}" ]; then
# 不存在开始下载
printInfo "首次需要下载hdc工具,2M"
URL="https://gitee.com/zhiyangnie/install-shell/raw/master/tools.zip"
# 下载到当前目录的 tools.zip
# 使用 curl 下载
curl -o "$hdcZip" "$URL"
if [ $? -eq 0 ]; then
printInfo "下载成功,准备解压${hdcZip}..."
# 解压ZIP文件
unzip -o "$hdcZip" -d "${hdcTool}"
# 检查解压是否成功
if [ $? -eq 0 ]; then
printInfo "${hdcZip}解压成功"
# 删除zip
rm "$hdcZip"
else
printError "${hdcZip} 解压失败,请手动解压"
fi
else
printError "下载失败,请检查网络"
fi
fi
}

signHapAndHsp(){
appCertFile="sign/install.cer"
profileFile="sign/install.p7b"
keystoreFile="sign/install.p12"
keyAlias="zhiyang"
keyPwd="a123456A"
keystorePwd="a123456A"
javaFile="lib/java"
hapSignToolFile="lib/hap-sign-tool.jar"
local item=$1
#遍历文件夹,拿到所有的hsp和hap去签名
for item in "${tmp}"/*; do
if [ -f "$item" ]; then
# 发送 以 .hsp 或 .hap 结尾。
if [[ "$item" == *.hsp || "$item" == *.hap ]]; then
# 开始签名
local inputFile="${item}"
outputFile=""
if [[ "$inputFile" == *.hap ]]; then
outputFile="${inputFile%.hap}-sign.hap"
else
outputFile="${inputFile%.hsp}-sign.hsp"
fi
signStatus=$(java -jar tools/lib/hap-sign-tool.jar sign-app -keyAlias "${keyAlias}" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "${appCertFile}" -profileFile "${profileFile}" -inFile "${inputFile}" -keystoreFile "${keystoreFile}" -outFile "${outputFile}" -keyPwd "${keyPwd}" -keystorePwd "${keystorePwd}" -signCode "1" 2>&1)
signStatus=$(${javaFile} -jar "${hapSignToolFile}" sign-app -keyAlias "${keyAlias}" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "${appCertFile}" -profileFile "${profileFile}" -inFile "${inputFile}" -keystoreFile "${keystoreFile}" -outFile "${outputFile}" -keyPwd "${keyPwd}" -keystorePwd "${keystorePwd}" -signCode "1" 2>&1)
if [[ "$signStatus" == *"failed"* || $signStatus == *"No such file or directory"* ]]; then
printError "签名失败,${signStatus}"
else
printDebug "签名成功,${inputFile} , ${outputFile}"
# printDebug "签名成功,${inputFile} , ${outputFile} , ${signStatus}"
#删除以前未签名的
rm -f "$inputFile"
fi
fi
fi
done
printInfo "签名完成"

}


# 判断是否已经下载过hdc文件
checkAndDownloadHdc

# 判断是否连接手机且仅有一个手机
devicesList=$(${hdcPath} list targets)

# 判断是否hdc 可用
if [ -z "$devicesList" ]; then
# 开始下载zip
print_error "hdc 不可用 ,请检查本目录是否存在 ${hdcPath}"
fi

# 判断是否连接手机,如果有 [Empty] 表明 一个手机也没连接
if [[ "$devicesList" == *"[Empty]"* ]]; then
printError "未识别到手机,请连接手机,打开开发者选项和USB调试"
fi


# 判断连接手机的个数
deviceCount=$(${hdcPath} list targets | wc -l)
if [ "$deviceCount" -ne 1 ]; then
printError "错误:连接的手机个数是 ${deviceCount} 个,请连接一个手机"
fi

printInfo "连接到手机,且仅有一个手机 ${devicesList}"



# 传过来的参数是 ,获取输入的 app 文件
appFile="$1"

# 判读传过来的路径文件是否以.app 结尾
if [[ ! "${appFile}" =~ .app ]]; then
printError "请传入正确的包路径,文件要 .app 结尾"
fi

# 判断文件是否存在
if [ ! -e "$appFile" ]; then
printError "不存在改文件 $appFile 。请确认"
fi

#------------------------------开始安装----------------------------------
# 开始安装
printInfo "开始安装应用, ${bundleName}"
# 1.先kill当前app的进程
$hdcPath shell aa force-stop "$bundleName"

# hdc shell mkdir data/local/tmp/c3af89b189d2480395ce746621ce6385
# 2.创建随机文件夹
randomHex=$(xxd -l 16 -p /dev/urandom)
randomFile="data/local/tmp/$randomHex"
mkDirSuccess=$($hdcPath shell mkdir "$randomFile" 2>&1)
if [ -n "$mkDirSuccess" ]; then
printError "手机中:随机创建文件夹 ${randomFile} 失败 , $mkDirSuccess"
else
printInfo "手机中:创建随机文件夹 ${randomFile} 成功"
fi
# 3.解压.app中
# 在本地创建 tmp 临时文件夹
tmp="tmp"
# 存在先删除
if [ -d "${tmp}" ]; then
rm -rf "$tmp"
fi
mkdir -p "$tmp"
# 解压.app ,使用 unUse 主要是 不想打印那么多的解压日志
unUse=$(unzip -o "$appFile" -d "$tmp")
if [ $? -eq 0 ]; then
printInfo "解压app成功"
else
printError "解压app失败,请传入正确的app。$appFile , "
fi

# 对所有的hap和hsp签名,此步骤一般是打包服务器比如jenkins去做的
signHapAndHsp "${tmp}"


printInfo "遍历解压发送到 手机的$randomFile"
# 4.遍历 tmp 文件夹中的文件发送到 randomFile 中
for item in "${tmp}"/*; do
if [ -f "$item" ]; then
# 发送 以 .hsp 或 .hap 结尾。
if [[ "$item" == *.hsp || "$item" == *.hap ]]; then
$hdcPath file send "$item" "$randomFile"
fi
fi
done
printInfo "成功发送到 手机的$randomFile "


# 5. 使用 install
# hdc shell bm install -p data/local/tmp/c3af89b189d2480395ce746621ce6385

installStatus=$($hdcPath shell bm install -p "$randomFile" 2>&1)
if [[ "$installStatus" == *"successfully"* ]]; then
printInfo "┌────────────────────────────────────────────────────────"
printInfo "│ ✅ 安装成功 "
printInfo "└────────────────────────────────────────────────────────"
${hdcPath} shell aa start -a "${entryAbility}" -b "$bundleName"
else
printf "\e[31m%s\e[0m\n" "┌────────────────────────────────────────────────────────"
printf "\e[31m%s\e[0m\n" "│❌ 安装错误"
echo "$installStatus" | while IFS= read -r line; do
printf "\e[31m%s\e[0m\n" "│${line}"
done
printf "\e[31m%s\e[0m\n" "│错误码:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/bm-tool-V5"
printf "\e[31m%s\e[0m\n" "└────────────────────────────────────────────────────────"

fi

# 6. 删除 手机端的 $randomFile
${hdcPath} shell rm -rf "$randomFile"
# 删除本地的tmp文件夹
rm -rf "$tmp"


# 如果执行 抱着错误 zsh: permission denied: ./a.sh
# 执行,如果没有x 比如像这样 -rw-r--r--
# ls -l install.sh
# 加入x
# chmod +x install.sh