android-day1- message and call ,adb

本文深入探讨了手机应用开发中的关键布局技术,包括LinearLayout、AbsoluteLayout、RelativeLayout、FrameLayout等,以及ADB命令的使用,如连接设备、安装卸载应用、发送短信和拨打电话。此外,还详细介绍了为按钮添加事件监听器的方法,涵盖内部类、匿名内部类、实现接口等多种方式。
1 五种部局
LinearLayout 线性布局
AbsoluteLayout 据对布局
RelativeLayout 相对布局
FrameLayout 帧布局 类似div层
tablelayout 表格布局
2 adb 简单命令
adb version
adb devices
adb shell
adb -s 制定连接那个设备
adb install demo.apk
adb uninstall [包名]
adb kill-server
adb start-server
adb pull
adb push
3 发短信
String number = send_number.getText().toString();
String content = send_content.getText().toString();
Log.i(tag, number);
Log.i(tag, content);
SmsManager smsManager = SmsManager.getDefault();
ArrayList<String> messages = smsManager.divideMessage(content);
smsManager.sendMultipartTextMessage(number, null, messages, null, null);
4 打电话
Intent intent = new Intent(); intent.setData(Uri.parse("tel:"+call_no));
intent.setAction(Intent.ACTION_CALL);
startActivity(intent);
5 给button添加消息的4种方法
内部类, 匿名内部类,自身实现onclicklistener接口,在配置文件里指定响应方法
import time import re import logging import os from http import HTTPStatus from dashscope import Application from adbutils import adb import uiautomator2 as u2 from emoji import replace_emoji from collections import deque ================== 日志配置 ================== logging.basicConfig( level=logging.INFO, format=“%(asctime)s [%(levelname)s] %(message)s”, handlers=[ logging.FileHandler(“auto_reply.log”, encoding=“utf-8”), logging.StreamHandler() ] ) logger = logging.getLogger(name) ================== 文本清洗 ================== def clean_text(s: str) -> str: “”“清洗聊天文本”“” s = replace_emoji(s, replace=‘’) # 去除表情符号 # 跳过无意义消息 if re.fullmatch(r"(已读|来自电脑端|\d{1,2}:\d{2})", s): return “” # 保留中英文、数字、基础标点 return re.sub( r’\w\s\u4e00-\u9fff.,!?;:,。!?;:', ‘’, s ).strip() ================== 设备配置 ================== class DeviceConfig: # 聊天列表入口XPath CHAT_ENTRY_XPATH = ( “/hierarchy/android.widget.FrameLayout[2]/android.widget.LinearLayout[1]/” “android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/” “android.widget.FrameLayout[1]/android.view.ViewGroup[1]/” “androidx.viewpager.widget.ViewPager[1]/” “androidx.recyclerview.widget.RecyclerView[1]/” “android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]/” “android.widget.FrameLayout[1]/androidx.viewpager.widget.ViewPager[1]/” “androidx.recyclerview.widget.RecyclerView[1]/” “android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/” “android.widget.FrameLayout[1]/android.view.ViewGroup[1]/” “android.view.ViewGroup[1]/android.widget.LinearLayout[1]/” “android.widget.RelativeLayout[1]/android.widget.LinearLayout[1]/” “android.widget.FrameLayout[1]/androidx.viewpager.widget.ViewPager[1]/” “androidx.recyclerview.widget.RecyclerView[1]/” “android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/” “androidx.recyclerview.widget.RecyclerView[1]/android.widget.RelativeLayout[1]/” “android.widget.TextView[1]” ) # 消息容器XPath MESSAGE_CONTAINER = ( "/hierarchy/android.widget.FrameLayout[2]/android.widget.LinearLayout[1]/" "android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/" "android.widget.FrameLayout[1]/android.widget.FrameLayout[1]/" "android.widget.RelativeLayout[1]/android.widget.RelativeLayout[2]/" "android.view.ViewGroup[1]/androidx.appcompat.widget.LinearLayoutCompat[1]/" "androidx.recyclerview.widget.RecyclerView[1]" ) # 输入框候选定位 INPUT_CANDIDATES = [ "//android.widget.EditText", # 通用 "//*[@resource-id='com.xxx:id/input']", # 根据实际包名 id ] SEND_BUTTON_XPATHS = [ '//*[contains(@text,"发送")]', '//*[@content-desc="发送"]' ] ================== AI配置 ================== class AIConfig: APP_ID = “1713e3abb11f4b08ad8c25dc43315ce9” # 替换为您的实际App ID MAX_HISTORY = 6 # 最大对话轮次 SCAN_INTERVAL = 2 # 扫描间隔(秒) MAX_RETRY = 3 # 最大重试次数 ================== 自动回复核心类 ================== class AutoReplier: def init(self, serial): self.d = self._connect_device(serial) self._setup_input_method() self.processed = set() # 已处理消息集合 self.messages = [] # 对话历史(不包含system prompt) self.msg_queue = deque() self.processing = False self.session_id = None # 用于多轮对话的session_id def _connect_device(self, serial: str): """连接安卓设备""" for _ in range(AIConfig.MAX_RETRY): try: d = u2.connect(serial) d.xpath.global_set("timeout", 10) logger.info(f"设备 {serial} 已连接") return d except Exception as e: logger.warning(f"连接失败:{e}") time.sleep(1) raise RuntimeError("设备连接失败") def _setup_input_method(self): """设置快速输入法""" try: self.d.set_fastinput_ime(True) logger.info("FastInputIME 已启用") except Exception as e: logger.warning(f"快速输入法启用失败:{e}") def _enter_chat(self) -> bool: """进入聊天窗口""" try: return self.d.xpath(DeviceConfig.CHAT_ENTRY_XPATH).click_exists(timeout=5) except Exception as e: logger.error(f"进入聊天窗口失败:{e}") return False def _get_new_messages(self): """获取未读消息""" messages = [] for i in range(3, 0, -1): xpath = ( DeviceConfig.MESSAGE_CONTAINER + f"/android.widget.LinearLayout[last()-{i -1}]/" "android.widget.RelativeLayout/android.widget.LinearLayout[1]/" + "android.widget.TextView[1]" ) el = self.d.xpath(xpath) if el.exists: txt = clean_text(el.get_text()) if txt and txt not in self.processed: messages.append(txt) return messages def _ask_ai(self, text: str) -> str: """调用AI生成回复""" for _ in range(AIConfig.MAX_RETRY): try: resp = Application.call( api_key=os.getenv("DASHSCOPE_API_KEY"), app_id=AIConfig.APP_ID, prompt=text, session_id=self.session_id ) if resp.status_code == HTTPStatus.OK: reply = resp.output.text.strip() self.session_id = resp.output.session_id # 更新session_id self.messages.extend([ {"role": "user", "content": text}, {"role": "assistant", "content": reply} ]) return reply except Exception as e: logger.warning(f"API调用异常:{e}") time.sleep(1) return "网络异常,请稍后重试" def _find_input_elem(self): """遍历候选 XPath,返回第一个存在的元素对象""" for xp in DeviceConfig.INPUT_CANDIDATES: el = self.d.xpath(xp) if el.exists: return el return None def _send_reply(self, text: str) -> bool: inp = self._find_input_elem() if not inp: logger.error("未找到输入框,消息未发送") return False try: inp.click() time.sleep(0.3) self.d.send_keys(text) time.sleep(0.3) except Exception as e: logger.error(f"输入消息失败:{e}") return False for xp in DeviceConfig.SEND_BUTTON_XPATHS: try: if self.d.xpath(xp).click_exists(timeout=1): return True except Exception as e: logger.warning(f"点击发送按钮失败:{e}") logger.error("未找到发送按钮,消息未发送") return False def _process_messages(self): """处理消息流程""" if self._enter_chat(): for msg in self._get_new_messages(): logger.info(f"新消息:{msg}") reply = self._ask_ai(msg) if reply: logger.info(f"生成回复:{reply}") if self._send_reply(reply): self.processed.update({msg, reply}) # 队列展示 logger.info(f"昵称:未知\n时间:{time.strftime('%H:%M:%S')}\n消息:{msg}\n回复内容:{reply}") # 返回聊天列表 self.d.press("back") time.sleep(0.3) self.d.press("back") time.sleep(0.3) def run(self): """主运行循环""" logger.info("自动回复服务启动") while True: try: self._process_messages() time.sleep(AIConfig.SCAN_INTERVAL) except RuntimeError as e: logger.error(f"运行时错误:{e}") break # 或根据需要进行重试 except Exception as e: logger.error(f"运行异常:{e}") if not adb.device_list(): logger.error("设备丢失,请检查设备连接。") break # 或根据需要进行重试 if name == “main”: devices = adb.device_list() if devices: AutoReplier(devices[0].serial).run() else: raise RuntimeError(“未检测到可用设备”) 优化下入口处理逻辑,在检测到 CHAT_ENTRY_XPATH = ( “/hierarchy/android.widget.FrameLayout[2]/android.widget.LinearLayout[1]/” “android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/” “android.widget.FrameLayout[1]/android.view.ViewGroup[1]/” “androidx.viewpager.widget.ViewPager[1]/” “androidx.recyclerview.widget.RecyclerView[1]/” “android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]/” “android.widget.FrameLayout[1]/androidx.viewpager.widget.ViewPager[1]/” “androidx.recyclerview.widget.RecyclerView[1]/” “android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/” “android.widget.FrameLayout[1]/android.view.ViewGroup[1]/” “android.view.ViewGroup[1]/android.widget.LinearLayout[1]/” “android.widget.RelativeLayout[1]/android.widget.LinearLayout[1]/” “android.widget.FrameLayout[1]/androidx.viewpager.widget.ViewPager[1]/” “androidx.recyclerview.widget.RecyclerView[1]/” “android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/” “androidx.recyclerview.widget.RecyclerView[1]/android.widget.RelativeLayout[1]/” “android.widget.TextView[1]” )多个此元素的相似元素出现时,遍历下所有动态元素入口的秒数或者分钟数,按照从小到大排列,从秒数最小的开始进行回复,需要完整版代码
05-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值