一、需求
最近有个需求出一个刷机工具(EXE),通过adb 复制文件 实现快捷按钮刷机 。
二、思路
1、配置刷机环境,
2、输入命令adb reboot bootloader进入机器人页面,点击flash-all.bat刷机,再次输入adb reboot bootloader进入机器人页面,最后输入fastboot boot D://twrp-3.2.1-0-marlin.img加载镜像文件,进入用户手动选取生成TWRP的文件步骤后,第一步算成功
3、删除TWRP文件夹下最后一层里的三个子文件,把rom包文件拷贝到该文件夹下
4、输入adb reboot bootloader命令进入机器人页面,再输入fastboot boot D://twrp-3.2.1-0-marlin.img加载镜像文件,进入用户手动选取生成的文件步骤后,刷机成功
三、配置刷机环境,
1:如果电脑上有adb,则跳过这一步,如果没有则需要先把“拷贝文件”里的四个文件复制到系统盘:/windows/system32和系统盘:/windows/system下。
2:手机连接电脑----开发者选项----USB调试----弹出来的调试信息里勾上。
3:电脑上打开驱动精灵,扫描驱动,如有关于adb的驱动就装上,没有就不管。
4:把twrp-3.2.1-0-xxxx.img文件放在D盘根目录下
5:确认手机连接到电脑,打开adb文件夹,按住键盘shift+鼠标右键,选择“在此处打开命令窗口”,输入adb devices确认是否连接成功,如下图。如果没找到手机则检查前面步骤是否正确。
四、关键代码实现
1、用代码打开cmd,实现输入adb命令
调用方法
psd = ExeCmd("adb devices");
private static string ExeCmd(string cmd)
{
System.Diagnostics.Process p = new System.Diagnostics.Process()
{
StartInfo = {
FileName = "cmd.exe",
UseShellExecute = false, //是否使用操作系统shell启动
RedirectStandardInput = true,//接受来自调用程序的输入信息
RedirectStandardOutput = true,//由调用程序获取输出信息
RedirectStandardError = true,//重定向标准错误输出
CreateNoWindow = true,//不显示程序窗口
}
};
p.Start();//启动程序
//向cmd窗口发送输入信息
cmd = string.IsNullOrEmpty(cmd) ? "exit" : $"{cmd}&exit";
p.StandardInput.WriteLine(cmd);
p.StandardInput.AutoFlush = true;
//p.StandardInput.WriteLine("exit");
//向标准输入写入要执行的命令。这里使用&是批处理命令的符号,表示前面一个命令不管是否执行成功都执行后面(exit)命令,如果不执行exit命令,后面调用ReadToEnd()方法会假死
//同类的符号还有&&和||前者表示必须前一个命令执行成功才会执行后面的命令,后者表示必须前一个命令执行失败才会执行后面的命令
//获取cmd窗口的输出信息
return p.StandardOutput.ReadToEnd();
}
2、判断手机设备是否连接(这里取得cmd返回的命令,因为返回的是长串命令行所以做了字符截取)
调用方法
string isphone = MidStrEx(psd, "\t", "\r\n\r\n");
public static string MidStrEx(string sourse, string startstr, string endstr)
{
string result = string.Empty;
int startindex, endindex;
try
{
startindex = sourse.IndexOf(startstr);
if (startindex == -1)
return result;
string tmpstr = sourse.Substring(startindex + startstr.Length);
endindex = tmpstr.IndexOf(endstr);
if (endindex == -1)
return result;
result = tmpstr.Remove(endindex);
}
catch (Exception ex)
{
Console.WriteLine("MidStrEx Err:" + ex.Message);
}
return result;
}
3、打开flash-all.bat刷机文件
string targetDir = string.Format(@"D:\XXX\XXX\");
Process proc = new Process();
string isok = ExecuteBAT(targetDir, proc);
private string ExecuteBAT(string strBatPath, Process pro)//文件路径;要执行bat文件的进程,返回执行结果
{
string mess = "";
try
{
pro.StartInfo.WorkingDirectory = strBatPath;
pro.StartInfo.UseShellExecute = true;
pro.StartInfo.FileName = "flash-all.bat"; //strBatPath是bat文件路径
pro.StartInfo.CreateNoWindow = true;
if (pro.Start())
{
//写日志
while (pro.WaitForExit(0) == false)
{
mess += pro.StandardOutput.ReadLine() + "\r\n";
}
}
else
{
mess = "0";
}
}
catch (Exception ex)
{
mess = ex.Message;
}
finally
{
pro.Close();
}
return mess;
}
4、获取要删除和移动的地址写的有点繁琐,文件夹地址不是固定的,每个手机生成的手机型号文件夹不一样,每次刷机的生成日期文件夹也不一样
比如:计算机\AOSP on XXXXX\内部共享存储空间\TWRP\BACKUPS\HT77K0202792\1972-11-12--05-10-40_aosp_marlin-userdebug_712_N2G47O_engcjc2020
\HT77K0202792\1972-11-12--05-10-40_aosp_marlin-userdebug_712_N2G47O_engcjc2020 这两个文件夹是动态生成的
所以要根据查询系统夹的命令一步步进行获取
//获取固定文件夹
string data1 = ExeCmd("adb shell ls -1 sdcard/TWRP/BACKUPS");
//获取手机名称
string phonename = MidStrEx(data1, "&exit\r\n", "\r\n");
string data2 = ExeCmd("adb shell ls -1 sdcard/TWRP/BACKUPS/" + phonename + "");
//获取文件名称
string flodername = MidStrEx(data2, "&exit\r\n", "\r\n");
//获取取得固定的三个子文件
var myfilelist = GetFileName(data2, phonename, flodername);
//获取最后一层文件夹的子文件方法
private static string[] GetFileName(string data, string phonename, string flodername)
{
string data3 = ExeCmd("adb shell ls -1 sdcard/TWRP/BACKUPS/" + phonename + "/" + flodername + "");
int index = data3.LastIndexOf("&exit");
String result = data3.Substring(index).Trim().ToLower();
//固定删除和移动子文件
string[] filenamelist = result.Split(new string[] { "\r\n" }, StringSplitOptions.None);
string[] results = filenamelist.Where(x => x != "&exit").ToArray();
return results;
}
这几个主要流程写下来,功能差不多就实现了
刚开始做的时候反向偏了,在找通过WPD读取便携式设备信息的相关资料,网上提供方法有问题,
第一种涉及到Interop.PortableDeviceApiLib.dll和Interop.PortableDeviceTypesLib.dll两个COM组件的引用,由于其是用c++编译的,对于有些方法的调用并不能得到正确的结果,要编译和反编译修改dll方法这些操作
第二种安装MediaDevices程序集,但是在代码中缺少字段,也不可用
后来才发现用adb命令实现简单得多
5、常用的adb命令
adb shell ls -l 查找所有文件
adb shell ls -1 /sdcard/xxx 查找系统文件夹下的所有文件夹
adb shell rm /sdcard/XX/XX 删除文件
adb push D:/XX/XX/XX.info sdcard/TWRP/XX 移动文件
对了在移动文件夹的时候 adb push D:/XX/data 我想要data下的所有文件,不要data这个文件夹名,但是这个写法移动过去把data文件夹一起移动过去了,后面没找到移动文件夹下的子文件的命令只能在data文件夹下,一个文件一个文件移动
6、我要在bat执行完成后获取返回的结果再加载下一个语句,但是没找到合适的方法去读取bat完成后的状态,只能设置等待时间Thread.sleep(),从执行bat开始等待到手机重启结束,这个感觉有点不友好,后面再研究下
7、注意事项
在打包好winform项目发给测试人员测试时,测试人员是W7的系统,在我电脑上运行得好好的,到他的电脑上执行bat命令时,提示
先找代码的原因,没问题,折腾了许久,最后才发现是adb环境变量没配置
配置好了后,就可以成功执行bat命令继续刷机操作了