ADB基础操作与Python环境配置
一、ADB基本操作介绍
ADB,全称Android Debug Bridge,是Google提供的一款用于Android平台设备(包括真机和模拟器)调试、交互和管理的命令行工具。通过ADB,开发者可以在电脑上对连接的Android设备执行一系列高级操作,如安装/卸载应用、推送/拉取文件、运行shell命令、截图、录制视频、查看日志等。
ADB采用客户端-服务器架构,包含以下三个主要组件:
- 客户端:在开发计算机上运行,接收用户输入的ADB命令并将其发送给服务器。
- 服务器:在开发计算机上作为后台进程运行,负责管理和转发客户端与设备间的所有通信。
- 后台程序(Daemon):在每台连接的Android设备或模拟器上作为后台进程运行,接收并执行服务器转发的命令。
ADB的基本操作包括但不限于:
adb devices
:列出所有已连接的Android设备。adb install <apk文件>
:安装应用。adb uninstall <包名>
:卸载应用。adb push <本地文件> <设备路径>
:将文件推送到设备。adb pull <设备文件> <本地路径>
:从设备拉取文件。adb shell
:进入设备的shell环境。adb tcpip 5555
:开启5555端口
二、所使用的Python库
为了更方便地与ADB进行交互,我们可以使用Python的第三方库,如pyadb
。pyadb
库提供了一组Python API,使得开发者可以使用Python代码来执行ADB命令,从而实现对Android设备的控制。
三、Python环境和各个库的下载
- Python环境下载: Python环境的下载可以根据操作系统的不同选择不同的安装包。对于Windows系统,可以下载Anaconda或Miniconda作为Python的包管理工具。Anaconda是一个包含了Python、conda包管理器和大量科学计算库的发行版,而Miniconda则是Anaconda的精简版,只包含了conda和Python。 下载链接可以在Anaconda的官方网站或各大软件下载网站上找到。
- pyadb库下载: 可以使用pip命令来安装pyadb库。在命令行中输入以下命令:
bash复制代码pip install pyadb
如果pip命令不可用,可能需要先安装Python和pip。
四、为了确保你的手机能够顺利进行开发者模式设置和网络调试,请按照以下步骤操作:
- 开启开发者模式:
- 进入手机的设置菜单。
- 找到“关于手机”或“系统信息”选项。
- 连续点击“版本号”或“构建号”七次,直到提示开发者模式已开启。
- 启用ADB调试:
- 在设置菜单中,进入“系统”或“高级设置”。
- 找到“开发者选项”并进入。
- 启用“USB调试”选项。
- 如果你的手机有无线调试选项,可以考虑开启以进行无线ADB调试。
- 连接ZeroTier网络:
- 打开ZeroTier应用。
- 确保已登录并连接到指定的局域网。
- 检查连接状态是否正常。
- 关闭防误触功能:
- 进入设置菜单,找到“智能辅助”或类似选项。
- 关闭“防误触”功能,以避免调试过程中误操作。
- 确保手机电量充足:
- 在开始调试之前,确保手机电量充足,建议保持在50%以上。
- 如果长时间调试,建议连接电源以防止电量不足导致中断。
按照以上步骤进行设置,确保手机处于最佳状态,方便进行开发和调试工作。
五、运行结果
一旦Python环境和pyadb库都安装成功,我们就可以编写Python脚本来执行ADB命令了。以下是一个简单的示例脚本,用于连接Android设备并检查设备是否已连接:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import subprocess
import random
import time
import cv2
import smtplib
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from datetime import datetime
import mimetypes
import os
import subprocess
# 定义ADB位置
ADB_PATH = "/usr/local/bin/platform-tools/adb"
# 定义设备ip,端口地址
DEVICE_IP_PORT = "10.132.246.118:5555"
# 定义截图文件路径
screenshot_file1 = "/mnt/python/image_zlt/screenshot1.png"
screenshot_file2 = "/mnt/python/image_zlt/screenshot2.png"
screenshot_file3 = "/mnt/python/image_zlt/screenshot3.png"
# 删除文件
def delete_files(*args):
"""
删除文件。
参数:
*args (tuple): 变量名和文件路径的元组。
"""
# 遍历参数元组,删除文件
for var_name, file_path in args:
if os.path.exists(file_path): # 确保文件存在
os.remove(file_path) # 删除文件
print(f"已删除文件:{file_path}")
else:
print(f"文件 {file_path} 不存在")
# 限定执行时间
def is_within_working_hours():
now = datetime.now()
start_time = now.replace(hour=8, minute=10, second=0, microsecond=0)
end_time = now.replace(hour=22, minute=0, second=0, microsecond=0)
return start_time <= now <= end_time
# 确认手机屏幕状态
def check_screen_state():
# 构造 adb shell 命令
command = [ADB_PATH, "-s", DEVICE_IP_PORT, "shell", "dumpsys", "power | grep 'Display Power: state='"]
try:
# 执行命令并捕获输出
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout_str = result.stdout.decode("utf-8")
if "Display Power: state=ON" in stdout_str:
return True # 屏幕处于亮屏状态
elif "Display Power: state=OFF" in stdout_str:
return False # 屏幕处于关闭状态
else:
return None # 无法确定屏幕状态
except subprocess.CalledProcessError as e:
print("执行命令失败:", e)
return None # 无法确定屏幕状态
# 连接设备
def connect_device():
command = [ADB_PATH, "connect", DEVICE_IP_PORT]
try:
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout_str = result.stdout.decode("utf-8")
if "connected to" in stdout_str:
print("连接成功")
return True
else:
print("连接失败")
return False
except subprocess.CalledProcessError as e:
print("连接失败:", e)
return False
# 截图
def take_screenshot(screenshot_file):
command = [ADB_PATH, "-s", DEVICE_IP_PORT, "shell", "screencap", "-p"]
with open(screenshot_file, "wb") as f:
subprocess.call(command, stdout=f)
# 比对前后图的差异
def calculate_mse(image1_path, image2_path):
# 读取图像并转换为灰度图
image1 = cv2.imread(image1_path)
image2 = cv2.imread(image2_path)
# 将图像转换为灰度图
gray1 = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
print("图片1转为灰度图成功")
gray2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)
print("图片2转为灰度图成功")
# 计算均方误差
mse = ((gray1 - gray2) ** 2).mean()
return mse
# 模拟滑动事件
def simulate_swipe(x, y, x1, y1):
command = [ADB_PATH, "-s", DEVICE_IP_PORT, "shell", "input", "swipe", str(x), str(y), str(x1), str(y1)]
subprocess.call(command)
time.sleep(2)
# 模拟点击事件
def simulate_tap(x, y):
while True:
take_screenshot(screenshot_file1)
print("模拟指令前截图完成")
command = [ADB_PATH, "-s", DEVICE_IP_PORT, "shell", "input", "tap", str(x), str(y)]
subprocess.call(command)
time.sleep(5)
take_screenshot(screenshot_file2)
print("模拟指令后截图完成")
mse = calculate_mse(screenshot_file1, screenshot_file2)
print("对比截图完成")
print("mse:", mse )
if mse >= 20:
break
# 模拟按键
def simulate_keyevent(keyevent):
command = [ADB_PATH, "-s", DEVICE_IP_PORT, "shell", "input", "keyevent", str(keyevent)]
subprocess.call(command)
time.sleep(2)
# 生成坐标随机数
def generate_random_coordinates(base_x, base_y):
random_offset_x = random.randint(-10, 10)
random_offset_y = random.randint(-10, 10)
random_x = base_x + random_offset_x
random_y = base_y + random_offset_y
return random_x, random_y
# 发送邮件
def send_email():
# 设置smtp所需要的参数
smtp_server = "smtp.qq.com" # 邮箱服务器
username = "1337047402@qq.com" # 账号
password = "xxxxxxxx" # 授权码
sender = "1337047402@qq.com" # 发邮件的人
receiver = ['1337047402@qq.com'] # 2个收邮件的人
subject = "打卡结果" # 邮件主题
# 构造邮件对象MIMEMultipart
# 主题、发件人、收件人、日期显示在邮件页面上
msg = MIMEMultipart('mixed')
msg['Subject'] = subject
msg['From'] = '1337047402@qq.com <1337047402@qq.com>'
msg['TO'] = ";".join(receiver)
# 获取当前时间并格式化为字符串
current_date = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
msg['Date'] = current_date
# 构造文字内容
text = "打卡成功"
text_plain = MIMEText(text, 'plain', 'utf-8')
msg.attach(text_plain)
# 构造图片
img_path = screenshot_file3
with open(img_path, 'rb') as img_file:
img_data = img_file.read()
img_type, _ = mimetypes.guess_type(img_path)
img_name = os.path.basename(img_path)
image = MIMEImage(img_data, img_type)
image.add_header('Content-Disposition', 'attachment', filename=img_name)
msg.attach(image)
# 发送邮件
try:
s = smtplib.SMTP()
s.connect(smtp_server, 25)
s.login(username, password)
s.sendmail(sender, receiver, msg.as_string())
print('发送成功')
finally:
s.quit() # 关闭 SMTP 连接
# 执行命令流程
if connect_device() and is_within_working_hours():
# 检查屏幕状态
screen_state = check_screen_state()
if screen_state is not None:
if screen_state:
print("屏幕处于亮屏状态,不执行操作")
else:
# 屏幕处于关闭状态,执行电源操作和滑动操作
print("执行电源操作和滑动操作")
simulate_keyevent(26) # 模拟电源操作
simulate_swipe(300, 1300, 300, 500) # 模拟滑动操作
else:
print("无法确定屏幕状态,不执行操作")
# simulate_keyevent(26) # 模拟电源操作
# simulate_swipe(300, 1300, 300, 500) # 模拟滑动操作
# 关闭指定应用程序
subprocess.call([ADB_PATH, "-s", DEVICE_IP_PORT, "shell", "am", "force-stop", "com.alibaba.android.rimet"])
time.sleep(2)
# 打开指定应用程序的启动活动
subprocess.call([ADB_PATH, "-s", DEVICE_IP_PORT, "shell", "monkey", "-p", "com.alibaba.android.rimet", "-c", "android.intent.category.LAUNCHER", "1"])
time.sleep(random.randint(20, 30))
# 模拟点击随机位置 打开打卡页面
random_coordinates = generate_random_coordinates(965, 427)
simulate_tap(*random_coordinates)
# 模拟点击随机位置 点击打卡
random_coordinates = generate_random_coordinates(550, 1250)
simulate_tap(*random_coordinates)
# 打卡成功截图
take_screenshot(screenshot_file3)
# 检查截图文件是否存在
if os.path.exists(screenshot_file3):
print("截图成功")
else:
print("截图还未成功,请等待会儿!")
time.sleep(5)
# 发送截图给目标
send_email()
# 调用函数并传入变量名和文件路径作为参数
delete_files(
("screenshot_file1", screenshot_file1),
("screenshot_file2", screenshot_file2),
("screenshot_file3", screenshot_file3)
)
# simulate_keyevent(66) # 模拟发送文本
subprocess.call([ADB_PATH, "-s", DEVICE_IP_PORT, "shell", "am", "force-stop", "com.alibaba.android.rimet"]) # 关闭指定应用程序
time.sleep(2)
simulate_keyevent(3) # 模拟返回键
simulate_keyevent(26) # 模拟电源操作
Comments | NOTHING