利用大柒悬浮按钮模板,做了一个能够修改QQ发送语音和闪照破解的脚本,为了能够使用,打包成apk文件。
流程介绍:
教程分为四部分,悬浮按钮的套用,QQ语音修改,闪照破解,主界面
一.悬浮按钮
悬浮按钮图:
最左边图标长按移动,点击会唤出右边的几个图标,这些图标是我利用设计logo的网站做出来的。
模板是从Auto.jsPro商店里下载的大柒的FloatMenu-Rhino-1.0.0.1。
使用方法就是将根目录下 `float_menu-rhino`文件夹放到你自己的项目,使用`require()`方法导入即可
const FloatMenu = require('./float_menu-rhino/index.js');
var fm = new FloatMenu();
//修改logoView参数
let logo = fm.getLogoView();
logo.setIcons("file://./logo.png");
logo.setRadius(10)
这里在测试时能够正常运行,但在打包成apk安装app运行后会报错闪退,原因是 `float_menu-rhino`目录modules文件夹下的view_util.js中第112行的inintLogoView函数在setIcon是会先初始化autojs的图标,但在打包成apk时是没有这个资源文件的,所以我们把它修改成autojs内置的图标。在第114行这样修改:
scope.logo_view.setIcons('@drawable/ic_android_black_48dp').setColors('#fafafa').attr('visibility', 'invisible');
随后添加图标右侧唤出按钮:
fm.addItem('按钮1')
.setColors('#3aff2851')
.setIcons('file://./语音1.png')
.setStroke(2, '#000000')
.onClick(view=>{
tihuan(yourqq) //语音修改函数
});
二.QQ语音修改
语音修改和闪照破解说白了就是文件的替换,只不过我把手动操作变成了脚本自动的操作。
替换路径:/storage/emulated/0/Android/data/com.tencent.mobileqq/Tencent/MobileQQ/你的qq号/ptt/日期/
要获得qq号和日期,才能顺利进入文件夹,qq号用户填写即可,日期代码获取。
获取日期:
Date.prototype.format = function(fmt) {
var year = this.getFullYear();
var month = this.getMonth() + 1;
var date = this.getDate();
fmt = fmt.replace("yyyy", year);
fmt = fmt.replace("yy", year % 100);
fmt = fmt.replace("MM", fix(month));
fmt = fmt.replace("dd", fix(this.getDate()));
return fmt;
function fix(n) { //补0,例如9转换成09
return n < 10 ? "0" + n : n;
}
}
var month = new Date().format("yyyyMM")//202209
var date = new Date().format("dd")//19
语音替换:
function tihuan(qq) {//自己手机登录的qq
var intent = new Intent();
intent.setType("audio/*");//跳转进入选择替换的音乐
/* 使用Intent.ACTION_GET_CONTENT这个Action */
intent.setAction(Intent.ACTION_GET_CONTENT);
activity.startActivityForResult(intent, 1);
var path = "/storage/emulated/0/Android/data/com.tencent.mobileqq/Tencent/MobileQQ/" + qq + "/ptt/" + month + "/" + date + "/" //1216951671/ptt/202209/15/1.mp3"
var arr = files.listDir(path);
var name = arr[arr.length-1] //获得录音的缓存文件名
activity.getEventEmitter().on("activity_result", (requestCode, resultCode, data) => {
if (requestCode == 1) { //返回结果处理
if (resultCode == -1) {
let uri = data.getData();
// let p = app.getPathFromUri(uri)
realpath = getfilepath(uri) //获得绝对路径
files.copy(realpath, path+"/"+name)//进行替换
toast("替换成功,点击发送")
app.startActivity(qqjump);//返回qq,随后点击发送即可
}
}
})
}
var qqjump = new Intent().setComponent(//返回qq意图
new ComponentName("com.tencent.mobileqq", "com.tencent.mobileqq.activity.SplashActivity") )//activity通过mt管理器获取
语音替换文件选择界面:
在替换的时候出现了问题,当选择替换的音乐时,回调返回的文件路径不是绝对路径,而是加密后的content://路径,这一点在文档中也有说明:
需要注意的是,在高版本Android上,由于系统限制直接在Uri暴露文件的绝对路径,因此如果uri字符串是文件
file://...
,返回的Uri会是诸如content://...
的形式。
使用牙叔的转换绝对路径函数解决这一问题:
function getfilepath(uri) {
//Source : https://www.cnblogs.com/panhouye/archive/2017/04/23/6751710.html
var r = null,
cursor,
column_index,
selection = null,
selectionArgs = null,
isKitKat = android.os.Build.VERSION.SDK_INT >= 19,
docs;
if (uri.getScheme().equalsIgnoreCase("content")) {
if (isKitKat && android.provider.DocumentsContract.isDocumentUri(activity, uri)) {
if (String(uri.getAuthority()) == "com.android.externalstorage.documents") {
docs = String(android.provider.DocumentsContract.getDocumentId(uri)).split(":");
if (docs[0] == "primary") {
return android.os.Environment.getExternalStorageDirectory() + "/" + docs[1];
}
} else if (String(uri.getAuthority()) == "com.android.providers.downloads.documents") {
uri = android.content.ContentUris.withAppendedId(
android.net.Uri.parse("content://downloads/public_downloads"),
parseInt(android.provider.DocumentsContract.getDocumentId(uri))
);
} else if (String(uri.getAuthority()) == "com.android.providers.media.documents") {
docs = String(android.provider.DocumentsContract.getDocumentId(uri)).split(":");
if (docs[0] == "image") {
uri = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if (docs[0] == "video") {
uri = android.provider.MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if (docs[0] == "audio") {
uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
selection = "_id=?";
selectionArgs = [docs[1]];
}
}
try {
cursor = activity.getContentResolver().query(uri, ["_data"], selection, selectionArgs, null);
if (cursor && cursor.moveToFirst()) {
r = String(cursor.getString(cursor.getColumnIndexOrThrow("_data")));
}
} catch (e) {
log(e);
}
if (cursor) cursor.close();
return r;
} else if (uri.getScheme().equalsIgnoreCase("file")) {
return String(uri.getPath());
}
return null;
}
三.QQ闪照破解
闪照路径:/storage/emulated/0/Android/data/com.tencent.mobileqq/Tencent/MobileQQ/cha
因为qq闪照的文件夹并不是正常按时间修改顺序排序的,所以要取到闪照首先要把之前的文件夹都给删干净,获取最新的缓存文件得到闪照。这个功能并不是很完善,由于操作问题也有可能得到别的图片。
先在悬浮按钮添加清除缓存的按钮:
fm.addItem('缓存').setIcons('file://./cache.png').setColors('#7aff2851')
.onClick(view=>{
let shanzhaopath = "/storage/emulated/0/Android/data/com.tencent.mobileqq/Tencent/MobileQQ/chatpic/chatthumb/"
files.removeDir(shanzhaopath)
toast("已删除缓存")
});
添加闪照保存的按钮:
fm.addItem('按钮2').setIcons('file://./闪照1.png').setColors('#fa99fa')
.onClick(view=>{
threads.start(function(){
shanzhao() //闪照保存函数
})
});
闪照保存:
function shanzhao(){
var shanzhaopath = "/storage/emulated/0/Android/data/com.tencent.mobileqq/Tencent/MobileQQ/chatpic/chatthumb/"
var savepath = "/storage/emulated/0/闪照保存/"
var arr = files.listDir(shanzhaopath);
var middle = arr[arr.length-1]
var middle1 = shanzhaopath+middle
var arr1 = files.listDir(middle1)
var shanzhaoname = arr1[arr1.length-1]
var frompath = middle1+'/'+shanzhaoname
var topath=savepath+shanzhaoname+".png" //保存成png文件
if(files.copy(frompath,topath)){
sleep(2000)//一定要延时,文件流操作堵塞会报错
media.scanFile(topath)//添加到媒体库,在系统自带相册即可看到
toastLog("请到相册查看")
}
}
四.主界面
ui.layout(
<vertical w="*" h="*" gravity="center" >
<input id="qq" w="*" h="auto" inputType="number" hint="请先输入已登录的QQ号,再打开悬浮窗"/>
<button id="xuanfu" w="*" h="auto" text="点击打开悬浮窗" textAllCaps="false" style="Widget.AppCompat.Button.Colored" />
<button id="quanxian" w="*" h="auto" text='点击检测悬浮窗权限' textAllCaps="false" style="Widget.AppCompat.Button.Colored" />
</vertical>
);
ui.quanxian.click(function(){
quanxian()
})
ui.xuanfu.click(function() {
let qqnumber = ui.qq.getText()
if (qqnumber != "") {
yourqq = qqnumber
fm.show();//打开悬浮窗
app.startActivity(qqjump);
}
else{
toast("请输入正确的QQ号")
}
})
悬浮窗权限:
function quanxian(){
if (!(new android.provider.Settings().canDrawOverlays(context))) {
toastLog("没有悬浮窗权限,将跳转到开启悬浮窗权限界面");
app.startActivity({
packageName: "com.android.settings",
className: "com.android.settings.Settings$AppDrawOverlaySettingsActivity",
data: "package:" + context.packageName.toString(),
});
} else {
ui.quanxian.setText("悬浮窗权限已打开")
toastLog("已有悬浮窗权限");
}
}
ui主界面: