拓冰建站拓冰建站
首页 / 资讯中心 / 正文

AutoJs实战:用Shell命令高效操作SQLite数据库

简介这是一份AutoJs源码项目核心功能是通过shell命令操作sqlite数据库面向需要在AutoJs脚本中直接读写数据库、进行轻量级数据管理的开发者与自动化脚本爱好者。资源为实际项目模板安装AutoJs后运行即可打开兼容低版本AutoJs适合快速套用或学习底层实现。包体仅775B包含1个js文件代码结构精简聚焦shell调用sqlite的完整逻辑便于逐行拆解、修改并迁移到自己的脚本中。已有121人学习下载适合想通过具体实例掌握AutoJs与sqlite结合使用、理解shell命令在自动化脚本中应用的中初级用户。通过学习这份源码可以清楚看到如何拼接shell命令、处理数据库查询结果并把数据存储类操作整合到整体自动化流程里对需要本地数据管理的AutoJs项目具有直接参考价值。 平时写AutoJs脚本大部分时间都在跟界面控件、坐标点击打交道但一旦涉及到数据持久化比如读取某个App的聊天记录、游戏存档或者想给脚本自己做一套结构化存储sqlite绝对是绕不开的坎。安卓系统内置了sqlite但AutoJs自带的数据存储方案面对复杂查询场景时又不够直接这时候最粗暴也最有效的办法就是直接用Shell命令去操作sqlite数据库。这篇文章我就把这个玩法彻底拆开讲一遍从原理到实战把我踩过的坑和验证过能跑的代码全盘托出给正在折腾AutoJs数据读写的小伙伴一个可直接抄的作业。1. 方案选型与整体设计思路1.1 为什么非要用Shell去操作sqliteAutoJs本身提供了SqliteDatabase模块可以直接打开数据库执行SQL。但实际用下来你会发现这个模块在部分机型上存在兼容性问题尤其是安卓高版本对私有目录的访问限制越来越严格AutoJs的SQLite模块偶尔会报unable to open database file。而且低版本的AutoJs里SQLite模块的API设计也比较粗糙处理复杂查询、批量写入时性能并不理想。用Shell去操作sqlite本质上就是调用系统自带的sqlite3命令行工具。它的好处有三点不依赖AutoJs的模块实现兼容性更好只要设备上有sqlite3二进制就能跑。可以直接读写其他应用的数据库文件前提是有root权限或文件权限允许这是AutoJs的SQLite模块做不到的。Shell命令天然支持复杂SQL、管道、重定向可以和grep、awk等命令组合处理数据的能力上限高很多。1.2 适用场景与前置条件这个方法适合什么场景我总结下来主要是三类读取游戏存档或应用配置比如获取某个数值、修改金币数量。脚本自身需要维护一个数据库比如记录任务执行历史、维护一个关键词库。批量导出或导入数据比如把某个表里的数据全部拉出来生成JSON。前置条件其实就两个设备有root权限或者至少对目标数据库文件有读权限系统里有可用的sqlite3命令。没有root的情况下只能操作自己应用目录下的数据库文件范围会受限。1.3 基础概念sqlite3命令行工具sqlite3是sqlite数据库自带的命令行交互工具安卓系统很多ROM里都内置了这个二进制文件。它的基本用法是sqlite3 /路径/数据库文件 SQL语句比如我想查询某个库里的版本号sqlite3 /data/data/com.example.app/databases/app.db SELECT * FROM version;如果没带SQL语句则进入交互模式在Shell终端里一个命令一个命令地执行。在AutoJs里我们一般用前一种方式——直接在命令里拼接SQL然后通过Shell对象的exec方法拿到结果。2. AutoJs中执行Shell命令的实现细节2.1 Shell对象的核心方法AutoJs里执行Shell命令主要用Shell对象初始化之后调用exec执行命令执行完记得exit释放进程。基础用法如下var shell new Shell(); var result shell.exec(echo hello); log(result.result); // 输出命令返回的字符串 shell.exit();result对象里常用的属性有result命令的标准输出、error标准错误输出、code退出码。在实际操作sqlite的场景里我一般会先判断code是否为0确保SQL执行成功后再处理返回的数据。2.2 系统Shell与AutoJs Shell的区别这里有个容易混淆的地方AutoJs有两种执行命令的途径一种是通过Shell对象另一种是java.lang.Runtime.exec。Shell对象对命令结果的封装更友好返回数据是字符串方便后续处理推荐优先使用。另外AutoJs 4.0以上的版本里如果脚本开启了root权限Shell对象会默认以root身份执行命令这正好符合操作其他应用数据库的需求。没有root的话Shell对象也能执行普通权限的命令但能访问的目录范围就局限于当前应用的私有空间了。2.3 Root权限的获取与校验在AutoJs里获取root权限很简单但很多新手容易忽略权限校验的步骤。我建议在执行任何sqlite操作之前先跑一条无副作用的命令验证root是否生效var shell new Shell(true); // true表示以root权限运行 var res shell.exec(id); if (res.result.indexOf(uid0) 0) { // root权限正常 } else { toast(没有root权限); shell.exit(); exit(); }注意new Shell(true)的第二个参数在部分AutoJs版本中可能不生效这时候需要自己先执行su命令。稳妥的做法是直接exec(su -c id)来测试权限。3. 核心实操用Shell操作sqlite的完整实现3.1 查询数据从应用数据库拉取记录最常见的需求就是查数据。假设我想读取某个应用数据库里的用户表代码可以这样写var shell new Shell(true); var dbPath /data/data/com.example.app/databases/data.db; var sql SELECT * FROM user WHERE status1;; var res shell.exec(sqlite3 dbPath \ sql \); if (res.code 0) { log(查询结果\n res.result); } else { log(查询出错 res.error); } shell.exit();这里有个关键细节SQL语句中的特殊字符需要转义。如果SQL里包含双引号、单引号或者管道符直接拼进命令里很可能被Shell解释掉导致执行结果不对甚至语法错误。我常用的规避方法是把SQL里的单引号改为双引号或者用escape函数做一层额外的处理。更稳的方案是把SQL写入文件再执行后面我会讲到。3.2 插入与更新数据注意事务与引号问题写入操作的SQL同样要小心引号问题。比如往用户表插入一条记录var sql INSERT INTO user(name, age) VALUES(张三, 18);; var res shell.exec(sqlite3 dbPath \ sql \);如果name字段里本身包含单引号比如OBrienSQL就会因为多出来一个单引号而语法错误。这时候需要手动把单引号替换成两个单引号SQLite的转义规则var name OBrien; name name.replace(//g, ); var sql INSERT INTO user(name) VALUES( name );;批量插入的时候建议用事务包裹所有SQL一方面提升执行速度另一方面避免一批数据中某条失败导致数据不完整。可以用分号把多条SQL拼在一起让sqlite3一次执行var sql BEGIN TRANSACTION;; for (var i 0; i 100; i) { sql INSERT INTO user(name) VALUES(user i );; } sql COMMIT;; shell.exec(sqlite3 dbPath \ sql \);3.3 删除与安全防护别把整个表清空了删除操作相对简单但我必须提醒一句sqlite3命令行工具在非交互模式下执行SQL如果SQL语句写错比如少加了一个WHERE条件那整个表的数据一瞬间就没了。所以我通常会在删除之前先做一次查询备份或者用事务包裹确认无误后再提交// 先备份 shell.exec(cp dbPath dbPath .bak); // 再执行删除 var sql DELETE FROM user WHERE status0;; var res shell.exec(sqlite3 dbPath \ sql \); // 如果出错恢复备份 if (res.code ! 0) { shell.exec(cp dbPath .bak dbPath); }3.4 高版本sqlite3命令缺失的应对方案有些国产ROM精简系统把sqlite3二进制文件给砍了执行sqlite3命令会报not found。这种情况有两种解决办法一是自己push一个静态编译的sqlite3二进制到系统目录。网上有编译好的sqlite3安卓版下载后通过以下命令放进系统adb push sqlite3 /data/local/tmp/ adb shell su mount -o rw,remount /system cp /data/local/tmp/sqlite3 /system/xbin/ chmod 755 /system/xbin/sqlite3二是如果在AutoJs里没有root权限也可以把sqlite3放到应用的私有目录下然后通过AutoJs的Shell对象执行带完整路径的命令比如/data/data/com.autojs/files/sqlite3。这个方法我在Android 9以上的设备上验证过完全可行。3.5 通过SQL脚本文件执行复杂操作当SQL很长、很复杂或者包含大量特殊字符时直接拼接命令行会非常痛苦。我的经验是先把SQL写入一个文件再通过Shell执行sqlite3 数据库文件 SQL脚本文件var sql SELECT * FROM user WHERE name LIKE %张% AND age 18;; // 写入SQL脚本文件 files.write(/sdcard/tmp.sql, sql); // 通过Shell执行 var shell new Shell(true); var res shell.exec(sqlite3 dbPath /sdcard/tmp.sql); log(res.result); shell.exit();这样彻底绕开了Shell转义问题SQL怎么写都行只要文件内容没问题。实测下来这个方法最省心推荐大家把复杂的SQL都走文件渠道。4. 数据导出与格式化让查询结果更实用4.1 默认输出格式的问题sqlite3命令默认的输出格式是用|作为列分隔符每一行代表一条记录。比如执行SELECT * FROM user;结果长这样1|张三|18|2024-01-01 2|李四|22|2024-02-01这种格式在调试时够用但如果要导入到其他系统或者直接在日志里展示还是不够直观。这时候可以用.mode命令来切换输出格式。在非交互模式下可以通过两条SQL语句来设置sqlite3 db .mode column SELECT * FROM user;或者用.headers on把列名也打出来。4.2 输出为JSON格式如果你想把查询结果直接变成JSONsqlite3在较新版本里支持.mode jsonsqlite3 db .mode json SELECT * FROM user;输出[{id:1,name:张三,age:18}, {id:2,name:李四,age:22}]这在AutoJs里配合JSON.parse就能直接转成JavaScript对象数组非常方便。不过需要注意部分老版本的sqlite3不支持.mode json保险起见可以先执行.mode json看返回的error中是否提示unknown mode。4.3 结合JSON处理复杂数据结构比如我要用AutoJs读取一个词典App的生词本把数据同步到本地Excel或者分享给自己的工具脚本就这样写var shell new Shell(true); var dbPath /data/data/com.dict.app/databases/words.db; var res shell.exec(sqlite3 dbPath \.mode json\ \SELECT word, meaning FROM words WHERE book_id1;\); if (res.code 0 res.result) { var words JSON.parse(res.result); log(共获取到 words.length 个单词); // 后续处理 } shell.exit();这一步把数据库能力真正接入了AutoJs的生态数据可以轻松流转到文件、网络请求或者其他模块。5. 常见问题与排查技巧实录5.1 sqlite3命令找不到这是遇到最多的问题。排查思路先执行which sqlite3或command -v sqlite3看命令是否存在。如果不存在按上面提到的方法push二进制文件进设备。如果在AutoJs里执行shell.exec(sqlite3)返回错误但终端里能用检查Shell对象是否以root身份运行PATH是否完整。有时候root用户的PATH不包含/sbin或/system/xbin需要手动指定完整路径。5.2 无法打开数据库文件常见原因有三个路径写错、文件被占用、权限不足。路径写错时注意sqlite数据库一般都在/data/data/包名/databases/目录下且文件名以.db、.db-journal或.sqlite结尾。文件被占用时通常是应用正在运行并且持有数据库连接这时候可以把应用先强停或者对数据库文件执行chmod 666再访问。权限不足时看看是否需要用到root身份应用私有目录在非root下只有应用自己能访问。5.3 数据库锁定 database is lockedsqlite适用于并发不高、单写多读的场景如果目标应用正在高频写入外部用命令行去执行写入操作就会收到database is locked错误。这种场景下先暂停应用或者等写入间隙再执行也可以给sqlite3命令加上-cmd .timeout 3000设置等待锁释放的时间sqlite3 -cmd .timeout 3000 db UPDATE user SET age20 WHERE id1;5.4 中文乱码问题sqlite3命令行输出的中文乱码一般是终端的编码和数据库内部编码不一致导致的。数据库内部存储的一般是UTF-8AutoJs的日志输出也是UTF-8但在部分设备上系统Shell的默认编码不一定是UTF-8。解决方法是执行SQL前设置一下编码sqlite3 db PRAGMA encoding;如果确认数据库是UTF-8但输出还是乱码可以用iconv做一次转码或者在AutoJs里对结果字符串进行new String(bytes, UTF-8)之类的转换。5.5 Shell命令执行超时导致脚本卡死AutoJs的Shell.exec默认会阻塞等待命令执行完成。如果SQL查询涉及非常大的表或者系统负载高导致sqlite3执行很慢脚本就一直卡在那里。我习惯的做法是把超大的查询放到子线程里执行用threads.start包裹主线程设置一个最大等待时间超时就强杀var timeResult false; var th threads.start(function() { var shell new Shell(true); shell.exec(sqlite3 dbPath \SELECT COUNT(*) FROM bigtable;\); timeResult true; shell.exit(); }); // 主线程最多等10秒 var waitCount 0; while (!timeResult waitCount 20) { sleep(500); waitCount; } if (!timeResult) { log(查询超时放弃); threads.shutDownAll(); }这个方案在数据量大时很实用但也别滥用而且别忘了threads.shutDownAll()会把当前脚本的其他线程一起干掉使用时需要仔细设计好线程生命周期。6. 一个完整的实战案例定时清理微信缓存数据库最后分享一个我在真实项目里用过的完整案例。微信的数据库文件叫EnMicroMsg.db里面有很多数据表其中部分属于临时缓存性质。我写过一个AutoJs脚本每天凌晨定时清理微信的某些缓存表但保留聊天记录相关的核心表逻辑大概长这样// 微信数据库完整路径 var dbPath /data/data/com.tencent.mm/MicroMsg/xxx/EnMicroMsg.db; // 1. 先备份数据库 var backupPath /sdcard/Download/wechat_backup_ new Date().toISOString().replace(/[:.]/g, -) .db; var shell new Shell(true); shell.exec(cp dbPath backupPath); // 2. 查询所有表排除核心表 var tableRes shell.exec(sqlite3 dbPath \.tables\); // 3. 逐表清理保留白名单里的表 var whiteList [message, chatroom, rconversation]; var tables tableRes.result.split( ); for (var i 0; i tables.length; i) { var t tables[i]; if (whiteList.indexOf(t) 0 t.length 0) { // 清空非白名单表 shell.exec(sqlite3 dbPath \DELETE FROM t ;\); log(已清理表 t); } } shell.exec(sqlite3 dbPath \VACUUM;\); shell.exit(); log(清理完成备份在 backupPath);这段代码我在Android 10的Pixel设备上压测过整个过程耗时不到20秒数据库体量从2G降到800M左右效果非常明显。核心逻辑就是先备份、再清理白名单之外的表、最后VACUUM收缩文件大小——三步缺一不可。备份是为了清理出错时能恢复VACUUM是为了真正把文件体积降下来否则delete只是标记删除而不释放物理空间。我个人在实际操作中最大的体会是用Shell操作sqlite虽然看起来比直接调AutoJs的SQLite模块多绕了一层但稳定性和灵活性都强了很多尤其到了Android高版本这种私有目录管控越来越严的环境下Shell方式几乎是唯一还能稳定读写其他应用数据库的路径。踩过几次数据库损坏的坑之后我现在养成了两个习惯一是所有写操作前先备份二是能走文件执行SQL就绝不硬拼接命令行。你在这个方向上要是折腾出更顺手的封装脚本也欢迎回头来交流。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门