Android FileChannel实现快速复制

发布于 2021-05-22  20 次阅读


一段时间,核善的老板说要做一个短视频平台的云端控制,实现一台电脑控制大约300台安卓手机进行平台养号、引流等操作,让我给出评估报告,处于保住饭碗的考虑,我都没认真思考,当前就给出答复,肯定可以做的。截至目前,实现了某音、某手和视频号三大平台的 发送私信","回复私信","搜索用户发私信","自动发文""自动带货","自动统计"......今天老板又说要进军直播了,让我加一个几百台手机同时涌入直播间给我们公司艺人发弹幕、发评论的功能。OK. I am fine!

不废话了,上干货,因为上面的需求已经不是之前做的那种我认知里面的Android APP。算是第一次接触脚本类的APP,也是折腾了一段时间。为了祭奠那些为此牺牲的头发,必须更博记录

分析:首先,研究对象是某音、某手和视频号,破解加密算法逆向接口Xposed这些我就直接放弃了,一是因为胳膊拧不过大腿(其实就是因为自己太菜),二是因为我不想为了这点工资领一副金手镯。所以,我决定用Android辅助服务AccessibilityService实现所有需求。这也是本文主要记录的内容,至于云端控制的实现,可以点击这里查看。在功能开发工程中,因为是边学边做,还是遇到了不少问题。但值得记录的也就以下几点
1. 节点获取工具推荐使用大神的uiautomator
配置环境之后,运行起来就如图所示

这样原生页面的每一个控件基本上都会有一个Id或者文字,利用AccessibilityService的findAccessibilityNodeInfosByViewId或者findAccessibilityNodeInfosByText就能找到当前页面的控件为所欲为了,自动抢红包,自动收能量,自动......刺不刺激?但是请注意,上面特意强调了一下是原生页面可以这样,如果是一个webview页面,控件可没这么好找。Android 辅助服务AccessibilityService寻找WebView控件,请查看这里

回归主题,先上干货

    /**
     * 快速复制单个文件
     *
     * @param oldPathName 原文件路径
     * @param newPathName 复制后路径
     */
    public static boolean fastCopy(final String oldPathName, final String newPathName, Handler mHandler) {
        boolean isFinish = false;
        try {
            File fromFile = new File(oldPathName);
            File targetFile = new File(newPathName);
            fileInputStream = new FileInputStream(fromFile);
            fileOutputStream = new FileOutputStream(targetFile);
            fileChannelOutput = fileOutputStream.getChannel();
            fileChannelInput = fileInputStream.getChannel();
            ByteBuffer buffer = ByteBuffer.allocate(4096);
            long transferSize = 0;
            long size = new File(oldPathName).length();
            int tempP = 0;
            int progress = 0;
            while (fileChannelInput.read(buffer) != -1) {
                buffer.flip();
                transferSize += fileChannelOutput.write(buffer);
                progress = (int) (transferSize * 100 / size);
                if (progress > tempP) {
                    tempP = progress;
                    Message message = mHandler.obtainMessage(0);
                    Bundle b = new Bundle();
                    b.putInt("progress", progress);
                    message.setData(b);
                    mHandler.sendMessage(message);
                }
                buffer.clear();
            }
            isFinish = true;
        } catch (Exception e) {
            isFinish = false;
        } finally {
            try {
                fileOutputStream.close();
                fileInputStream.close();
                fileChannelOutput.close();
                fileChannelInput.close();
            } catch (IOException e) {
                e.printStackTrace();
                isFinish = false;
            }
        }
        return isFinish;
    }

      /**
     * 接收消息处理
     */
    private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {

            Bundle b = msg.getData();
            int progress = b.getInt("progress");
            flag++;
            if (flag % 10 == 0) {
                Toast.makeText(MyApp.getContext(), "正在排序:进度" + progress + "/" + 100, Toast.LENGTH_SHORT).show();
            }

        }
    };

如果用普通的byte[] buffer = new byte[1024 * 10];这样写关键问题在1024 * 10这个位置,我根本不知道手机硬盘读写的上限,而且每款手机还不一样,折腾了蛮久,初步测试该代码拷贝200M的视频只花了6秒(超出预期一大截)

最后记录一下,该功能使用场景。脚本控制短视频平台自动发文,视频源一开始存放在手机本地,虽然命名有先后顺序,但是相册的排序并不是按文件名来的,二是根据文件创建的时间从近到远。所以我进行复制一份的最终目的就是将指定的对应mp4移动到相册第一个,这样每次就能发送与账号对应的作品了,你学废了吗?

脚本源码开源怕被老板屌 ,有需要的在下方评论区留下联系方式。我悄咪咪的发你。Wink


现在住在心里的人,以后也要住进家里。