通过MediaProjectionManager的录屏操作,做了个简单的应用,但是每次都把自身的悬浮框录制了进去,脑壳疼。使用系统自带的录屏工具就不会有这个问题。为了一探究竟,捣鼓出了系统的录屏工具apk后,导出查看代码的方式可以参考操作指引,查看了下代码。得到了一份解决方案,附上工具类的代码。思路就是伪造window的标题和flag
package com.ux.xposed.utils;
import android.graphics.PixelFormat;
import android.os.Build;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.WindowManager;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
public class RecorderFakeUtils {
private static final String TAG = "RecorderFakeUtils";
public static final String ROM_MIUI = "MIUI";
public static final String ROM_EMUI = "EMUI";
public static final String ROM_FLYME = "FLYME";
public static final String ROM_OPPO = "OPPO";
public static final String ROM_SMARTISAN = "SMARTISAN";
public static final String ROM_VIVO = "VIVO";
public static final String ROM_QIKU = "QIKU";
private static final String KEY_VERSION_MIUI = "ro.miui.ui.version.name";
private static final String KEY_VERSION_EMUI = "ro.build.version.emui";
private static final String KEY_VERSION_OPPO = "ro.build.version.opporom";
private static final String KEY_VERSION_SMARTISAN = "ro.smartisan.version";
private static final String KEY_VERSION_VIVO = "ro.vivo.os.version";
private static String sName;
private static String sVersion;
//华为
public static boolean isEmui() {
return check(ROM_EMUI);
}
//小米
public static boolean isMiui() {
return check(ROM_MIUI);
}
//vivo
public static boolean isVivo() {
return check(ROM_VIVO);
}
//oppo
public static boolean isOppo() {
return check(ROM_OPPO);
}
//魅族
public static boolean isFlyme() {
return check(ROM_FLYME);
}
//360手机
public static boolean is360() {
return check(ROM_QIKU) || check("360");
}
public static boolean isSmartisan() {
return check(ROM_SMARTISAN);
}
public static String getName() {
if (sName == null) {
check("");
}
return sName;
}
public static String getVersion() {
if (sVersion == null) {
check("");
}
return sVersion;
}
public static WindowManager.LayoutParams getFakeRecorderWindowLayoutParams() {
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (isMiui()) {
layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
} else {
layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
}
} else {
layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}
layoutParams.format = PixelFormat.RGBA_8888;
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
layoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;//悬浮框在布局的位置
layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;//悬浮窗的宽,不指定则无法滑动
layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;//悬浮窗的高,不指定则无法滑动
layoutParams.x = 0; //初始位置的x坐标
layoutParams.y = 0; //初始位置的y坐标
layoutParams.setTitle(RecorderFakeUtils.getFakeRecordWindowTitle());
if (check(ROM_FLYME)) {
setMeizuParams(layoutParams, 0x2000);
}
if (check(ROM_MIUI)) {
//不要问我为啥写成这样,因为小米自带的截屏软件 就是写的这个鬼标识
layoutParams.flags = 4136;
}
return layoutParams;
}
/**
* 这丫的自定义了特殊的参数
* @param params
* @param flagValue
*/
private static void setMeizuParams(WindowManager.LayoutParams params, int flagValue) {
try {
Class MeizuParamsClass = Class.forName("android.view.MeizuLayoutParams");
Field flagField = MeizuParamsClass.getDeclaredField("flags");
flagField.setAccessible(true);
Object MeizuParams = MeizuParamsClass.newInstance();
flagField.setInt(MeizuParams, flagValue);
Field mzParamsField = params.getClass().getField("meizuParams");
mzParamsField.set(params, MeizuParams);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 总结下可以操作的是华为,魅族,oppo
* @return
*/
public static String getFakeRecordWindowTitle() {
if (sName == null) {
check("");
}
if (sName == null) {
return "";
}
switch (sName) {
case ROM_MIUI:
return "com.miui.screenrecorder";
case ROM_EMUI:
return "ScreenRecoderTimer";
case ROM_OPPO:
//oppo手机的悬浮框截屏,每次都需要弹出授权框,我去,这就很尴尬了
return "com.coloros.screenrecorder.FloatView";
case ROM_VIVO:
return "screen_record_menu";
case ROM_SMARTISAN:
break;
case ROM_FLYME:
return "SysScreenRecorder";
}
return "";
}
public static boolean check(String rom) {
if (sName != null) {
return sName.equals(rom);
}
if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_MIUI))) {
sName = ROM_MIUI;
} else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_EMUI))) {
sName = ROM_EMUI;
} else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_OPPO))) {
sName = ROM_OPPO;
} else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_VIVO))) {
sName = ROM_VIVO;
} else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_SMARTISAN))) {
sName = ROM_SMARTISAN;
} else {
sVersion = Build.DISPLAY;
if (sVersion.toUpperCase().contains(ROM_FLYME)) {
sName = ROM_FLYME;
} else {
sVersion = Build.UNKNOWN;
sName = Build.MANUFACTURER.toUpperCase();
}
}
return sName.equals(rom);
}
public static String getProp(String name) {
String line = null;
BufferedReader input = null;
try {
Process p = Runtime.getRuntime().exec("getprop " + name);
input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024);
line = input.readLine();
input.close();
} catch (IOException ex) {
MyLogUtils.d(TAG, "Unable to read prop " + name + ex);
return null;
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return line;
}
18 条评论
你好博主,根据你的文章,我尝试了一下自己写投屏过滤.按照文章提供的思路,我的想法是系统自带的“屏幕录制”他的悬浮窗是被系统判定只会在手机上显示的,所以他不会在其他任意的投屏环境下显示。那么我们想做绘制过滤外设过滤的效果的话,就将想要过滤的外设或者绘制悬浮窗属性更改为系统自带的“屏幕录制”,这样来欺骗系统让系统不把他投出去。但是这样辅助的绘制会投出去吗。因为没有接触过辅助这一块的东西,会不会导致只过滤的辅助的悬浮窗而辅助本身的绘制还是投屏出去了呢。
谢谢博主分享 我想自己找一下vivo的系统 是从安装包里面找吗
是的,自己提取系统录像的app,然后进行分析即可
重金求写一个小新pad pro12.6的过直播
应该是 privateFlags 赋值2097152
看个标识就好了的呀
赞啊
博主可以透漏下吗 重金必谢
不再免费分享,购卡地址:http://52o.ink/M1f
商品下架了,需要购买地址或者联系方式,谢谢。
在哪里购买?
已经不出售了
现在外面卖的好贵1000多半年
可以找你定制吗
牛蛙
牛蛙