June 9, 2021

Автоматизация Андроид Приложений

Шаблон со статьи: https://zennolab.com/discussion/threads/avtomatizacija-android-bez-posrednikov-chast-1.79012/

https://disk.yandex.ru/d/w1pxVQ2kC25MJw

Содержимое файла консультации:

1. Инструменты
Appium

adb
https://zennolab.com/discussion/threads/avtomatizacija-android-bez-posrednikov-chast-1.79012/
adbkeyboard https://github.com/senzhk/ADBKeyBoard (установить её по умолчанию)

Любой функционаи дополняется умением работать с adb.

Zennodroid

2.Эмуляторы
Если работать на сервере, то необходима видеокарта + виртуализация.
Memu
https://www.memuplay.com/blog/how-to-manipulate-memu-thru-command-line.html

После установки эмулятори (или обновления) необходимо зайти в папку с эмулятором и заменить adb файлы эмулятора на adb с built tools.

Обращение к нужному экземпляру эмулятори
adb -s 127.0.0.1:21513 КОМАНДА

a.Wait("//node[@resource-id='com.cyanogenmod.filemanager:id/navigation_view_item_name' and @text='storage']", 0, 10); //XPath, Index, Секунды

3.Анонимность
Для телефонов
Xposed + модули. Device faker, Device Emulator pro
https://4pda.ru/forum/index.php?showtopic=425052

Для эмуляторов лучше создать новый эмулятор.

4.Прокси как установить.
В самом android приложении:
-Proxydroid (не проксирует DNS)
-Drony

-В разделе "полезное" (ниже) через сниппет

5. Курсы
https://cloud.mail.ru/public/4jXc/51RHwKWra/


1. Cтавим прокси через Drony (через вкладку "вай-фай", а не через "остальные сети")

2. Меняем раскладку на ру.

а) Через АРК устанавливаем .арk файл клавиатуры

Или устанавливаем .apk с помощью сниппета:

var a = project.Context["ADB"];
var device = a.Device();
SharpAdbClient.DeviceCommands.PackageManager manager = new SharpAdbClient.DeviceCommands.PackageManager(device);
try {
manager.UninstallPackage("com.google.android.youtube"); //удаление пакета
} 
catch (Exception e) {}
manager.InstallPackage(project.Directory + @"\youtube.apk", reinstall: false); //установка apk

После установки, нажать на рабочем столе на иконку чтобы установилось

Далее через консоль cmd установить ADBkeyboard клавиатуру по умолчанию

adb shell ime set com.android.adbkeyboard/.AdbIME

После проверить клавиатуру на работоспособность через консоль командой

adb shell am broadcast -a ADB_INPUT_TEXT --es msg 'Привет?'

И уже в самом PM проверить чтобы в using была команда

using System.Diagnostics;

И сам сниппет для ввода текста через РМ:

var sn = project.Variables["threads_tel_sn"].Value; //тут серийник устройства для многопотока вида 127.0.0.1:21503
ProcessStartInfo startInfo1 = new ProcessStartInfo();
startInfo1.FileName = "adb.exe";
startInfo1.Arguments = "-s "+sn+" shell am broadcast -a ADB_INPUT_TEXT --es msg 'Привет'";
startInfo1.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(startInfo1).WaitForExit();

Что я ещё делаю:

  1. Меняю язык системы на английский чтобы проще было находить элементы. (за элементы на русском путь по xpath не работает).
  2. Устанавливаю галерею.

Чтобы узнать путь, куда загружать фотки чтобы они были в галерее:

И затем по этому пути заливаем папку с изображениями.

Полезное:

Для мему Get Pid

lock(SyncObject) {
var gbVar = project.GlobalVariables["Zappium", "process"];
Process[] processes = Process.GetProcessesByName("MEmuHeadless");
var ids = processes.Select(p => p.Id);
string process = "";
foreach(int processId in ids){
    //project.SendInfoToLog(processId.ToString());
    process = processId.ToString();
    if (project.Variables["process"].Value == String.Empty && !project.GlobalVariables["Zappium", "process"].Value.ToString().Contains(process)){
        project.Variables["process"].Value = process;
        gbVar.Value = gbVar.Value + process + ";";
        return process;
        }
}
throw new Exception("Нет свободных эмуляторов");
}

Get Device

Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.UseShellExecute = false;
cmd.Start();

cmd.StandardInput.WriteLine(String.Format("netstat -a -n -o | find \"{0}\" | findstr \"21.*3\"",project.Variables["process"].Value));

cmd.StandardInput.Flush();
cmd.StandardInput.Close();
cmd.WaitForExit();

return "127.0.0.1:" + Regex.Match(cmd.StandardOutput.ReadToEnd(), "(?<=127.0.0.1:)21.*3(?= )");

Сниппеты:

Переход на сайт

ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = @"adb";
startInfo.Arguments = @"shell am start -a android.intent.action.VIEW -d http://zennolab.com";
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(startInfo).WaitForExit();

Ввод текста

var sn = project.Variables["threads_tel_sn"].Value;//тут серийник устройства для многопотока вида 127.0.0.1:21503
ProcessStartInfo startInfo1 = new ProcessStartInfo();
startInfo1.FileName = "adb.exe";
startInfo1.Arguments = "-s "+sn+" shell am broadcast -a ADB_INPUT_TEXT --es msg 'Привет'";
startInfo1.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(startInfo1).WaitForExit();

Поставить прокси конкретному потоку:

a.Command("settings put global http_proxy 354.574.57.90:8080", false);

Возврат ответа в переменную:

Process p = new Process();
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "adb.exe";
p.StartInfo.Arguments = @"-s "+sn+" shell dumpsys battery | grep 'level'";
p.StartInfo.CreateNoWindow = true;
p.Start();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
project.Variables["battery_level"].Value = output.Trim();

Сниппет для ввода команд Memu с получением ответа от команд

System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.StandardOutputEncoding = Encoding.GetEncoding(866);
p.StartInfo.FileName = @"D:\Program Files\Microvirt\MEmu\memuc.exe"; // путь к батнику или exe
p.StartInfo.Arguments = @" listvms running"; // его параметры
p.Start();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit(); // ожидание завершения процесса
return output;

Перезагрузка эмулятора:

System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.StandardOutputEncoding = Encoding.GetEncoding(866);
p.StartInfo.FileName = @"D:\Program Files\Microvirt\MEmu\memuc.exe"; // путь к батнику или exe
p.StartInfo.Arguments = @" reboot -i 0"; // его параметры
p.Start();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit(); // ожидание завершения процесса
return output;

Перемещение картинки:

//ПЕРЕМЕЩАЕМ КАРТИНКУ В ГАЛЕРЕЮ
string pat_ishodniy = @"C:\Users\User\Desktop\AAA\iHappy_img";
var List = project.Lists["Файлы"];
string supportedExtensions = "*.jpg,*.gif,*.png,*.bmp,*.jpe,*.jpeg,*.wmf,*.emf,*.xbm,*.ico,*.eps,*.tif,*.tiff,*.g01,*.g02,*.g03,*.g04,*.g05,*.g06,*.g07,*.g08";
foreach (string imageFile in Directory.GetFiles(pat_ishodniy, "*.*", SearchOption.AllDirectories).Where(s => supportedExtensions.Contains(Path.GetExtension(s).ToLower())))
{
    List.Add(imageFile);
}
string pathFile = List[0].Trim();
string newNameFile = Regex.Match(pathFile, "(?<=iHappy_img\\\\).*(?=\\.jpg)").Value;
string pathNewDirectory = @"C:\Users\User\Pictures\MEmu Photo\photos55\"; // новая директория для файла.
//string newNameFile = "Мой перемещенный файл";
var fileInfo = new FileInfo(pathFile);
var directoryInfo = new DirectoryInfo(pathNewDirectory);
string newPathFile = Path.Combine(directoryInfo.FullName, newNameFile + fileInfo.Extension);
try
{
  if (!fileInfo.Exists) throw new Exception(quot;Файла не существует: {fileInfo.FullName}"); // проверяем файл на существование.
  if (!directoryInfo.Exists) Directory.CreateDirectory(directoryInfo.FullName); // проверяем директорию на существование, если её нет - создаем.
File.Move(fileInfo.FullName, newPathFile); // перемещаем файл.
project.SendInfoToLog(quot;Новый путь файла: {newPathFile}");
}
catch(Exception ex)
{
  project.SendWarningToLog(ex.Message); // вывод ошибки в лог.
}