Залетаем в ZennoDroid с 2х ног и получаем первую прибыль - кубики, c# + VS и подводные камни. БОНУС (решение кликовой яндекс капчи)

Sherminator

Client
Регистрация
10.09.2021
Сообщения
1 261
Благодарностей
679
Баллы
113
115297



Введение

Приветствую всех на 20-ом конкурсе статей форума ZennoLab!
В статье я поделюсь своим опытом в создании шаблонов на ZennoDroid, с учетом использования кубиков, C# и VisualStudio. Мой материал окажется полезным в первую очередь для тех кто только начинает знакомство с ZennoDroid. В статье я расскажу не только про технические аспекты, но и поделюсь собственными наработками.


Основы ZennoDroid для новичков с кубиками

В целом по кубикам отличий от зенопостера не так много, большая часть из них скопирована, появилась дополнительная вкладка под андроид, там и осуществляется основная работа с устройством.
2023-12-07_09-26-06.png

Быстрый старт осуществляется с помощью 4х кубиков: Создаем устройство, выбираем его, проксируем, запускаем.
Создание, выбор и запуск находятся во вкладке “Действия с устройством”, проксирование во вкладке “Настройки устройства”.
115266

В кубике с названием надо обязательно указать переменную для индекса создаваемого устройства (индекс генерируется автоматически), а в кубике выбора указать эту переменную что бы он по индексу выбрал нужное устройство.

Всё, машина запущена, можно начинать с ней работать.

Теперь немного нырнем в параметры устройства, вкладка “Настройки устройства”.
115267

В целом, сам ZennoDroid генерирует вполне сносные параметры, лично я в обязательном порядке меняю разрешение экрана, потому что по умолчанию там планшет получается и докидываю ядер с оперативкой, что бы устройство пошустрее было. Все настройки которые вы тут задаете они сохраняются в профиль.
115268

Что бы они применились, надо запускать устройство с параметром применения настроек профиля.
115269

Теперь попробуем мальца изменить параметры .

Если с настройкой IMEI, Android ID все понятно, то с оператором нужно знать некоторые моменты, они прописаны в документации ZennoDroid.

115270

Вот сайт с требуемыми данными https://www.mcc-mnc.com/

По поводу смены модели устройства, если с производителем всё понятно, то модель надо указывать (на пример для самсунга) не Galaxy s10+, а SM-G975X, иначе вы даже проверку устройства не пройдете при попытке авторизации в гугл плей.
Поля ro.product.brand и ro.product.board надо искать в файле build.prop для требуемой модели, файл этот находится в гугле за 5 минут.

Теперь после того как мы настроили устройство и запустили его, можно на него что-нибудь установить, для этого идем на вкладку “Действия с приложениями”. Установим яндекс браузер, для этого надо просто указать путь к апк файлу.
115271

Вот мы накатили наше первое приложение, теперь его надо запустить, для этого выберем в этом же кубике пункт “Открыть приложение”, нам надо указать имя приложения, для того что бы узнать его имя мы идем на вкладку “Установленные приложения” и там находим наш яндекс браузер и копируем его название, затем подставляем его в кубик и пробуем запустить.
115272

По такому же принципу (через название приложение) осуществляется работа с остальными опциями в кубике “Действия с приложениями”.


Управление через AdbShell

Ещё хотелось бы рассказать про Adb Shell команды которые упрощают некоторые действия. Кубик “Утилиты”, опция “Консольная команда”. Пробегусь по паре основных команд, в целом их создавать не так сложно, заходите в ChatGPT и он их очень ловко генерирует. Обязательно надо указывать переменную в которую положится результат выполнения кубика, а то он с ошибкой будет выполняться.

Команда которая открывает браузер по умолчанию и переходит на нужный нам URL.

adb shell am start -a android.intent.action.VIEW -d http://www.yahoo.com

Команда что бы открыть настройки приложения, в данном случая яндекс браузера, тут так же используется название приложения.

adb shell am start -a android.settings.APPLICATION_DETAILS_SETTINGS -d package:com.yandex.searchapp

Команда для открытия настроек разработчика.

adb shell am start -a android.settings.APPLICATION_DEVELOPMENT_SETTINGS

Команда что бы сделать скриншот.

adb shell screencap -p /storage/emulated/0/Download/screenshot.png

Скриншот сохраняется в папку Download (это основная папка для обмена файлами между эмулятором и пк) на пк это папка находится по пути C:\Users\UserName\Downloads\MEmu Download

В целом через adb shell команды очень удобно производить настройки самого устройства без создания лишних команд для тачей и свайпов.

Про свайпы и тачи будет дальше в статье, мне стандартное решение не нравится, предложу вам свое.


Подводные камни

За время работы с ZennoDroid заметил следующие неприятности.

1) Вес одной машины
Одно устройство весит довольно не мало 2 гб, чем больше вы с ним работаете тем больше оно будет весить. В итоге небольшая ферма на 500 устройств будет весить терабайт (как минимум).

2) Скорость работы устройства
В зависимости от сгенерированного устройства и используемых приложений, скорости интернета и мощности вашего пк будет зависеть успешность выполнения вашего шаблона, на пример, вы произвели запуск устройства, кубик завершился удачно, следующим у вас идет кубик запуска приложения, и он у вас выполняется не удачно, потому что устройство хоть и запустилось но оно не прогрузилось как следует, а ZennoDroid этот момент не ловит, в итоге вы приложение не запустите, так же произойдет ошибка если вы попробуете выполнить adb shell команду пока устройство не прогрузилось.

3) Создание большого количества машин
Если вы создаете в MEmu очень много машин, ну хотя бы 1000, у вас появится 2 очень неприятных проблемы. Первая, очень часто начнет вылетать ошибка при попытке создать новое устройство, иногда даже раз по 5 подряд. Вторая, после неудачной попытки создания, список устройств в Memu будет автоматически пролистывать до самого конца. Можете это увидеть вот тут https://zennolab.com/discussion/threads/prolistyvanie-spiska-ustrojstv.115103/

4) Одновременный запуск машин
Запуск большого количества потоков подтягивает проблему одновременного запуска машин, ресурсы на запуск как я понял делятся между машинами и чем больше вы машин одновременно запускаете, тем дольше будет производится запуск, тем больше шансов что шаблон упадет в ошибку из за таймаута на запуск машины.

А теперь расскажу вам как каждую из этих “Фичей” я решал.

1) По уменьшению веса машины я писал целую статью, можете с ней по ссылке ознакомиться. https://zennolab.com/discussion/threads/umenshenie-razmera-mashiny-zennodroid-dlja-xranenija.114499/

2) Тут всё конечно посложнее, универсального решения у меня нету, есть только советы, помнить о том что такая проблема есть и руками выставлять паузы перед действиями. У меня есть свой метод для ожидания элементов который частично решает проблему. Его я напишу в части про c#

3) Этот момент связан с первым пунктом, в той статье я допустил не большую ошибку (о которой я узнал позже), получается мы оставляли папку с машиной в мему и количество машин которые отображаются в memu постоянно росло. Сейчас делаю иначе. Алгоритм такой. Создаю новую машину, работаю с ней, потом файл disk2 перемещаю на хранение, а саму машину удаляю. Когда мне вновь надо поработать с этой машиной, я создаю новую машину, удаляю в ней файл disk2 и подкидываю туда свой disk2 который на хранение был, после работы убираю этот диск обратно на хранение а машину удаляю. В итоге у меня количество созданных эмуляторов в мему равно количеству потоков с которыми я работаю. Ну и ещё есть не большой момент. После обновления версии MEmu там меняются цифры в название файла disk2 и disk1, в итоге когда вы подкидываете свой файл disk2 надо будет ему сменить название на актуальные цифры которые используются в названии disk1.

4) Тут всё просто, если комп слабый, делаем лок, что бы у нас одновременно мог производить запуск только один эмулятор, если комп помощнее, делаем семафор и указываем сколько эмуляторов можно запускать одновременно. Этими двумя методами я с вами поделюсь в части про c#.


С#

Пробежимся по основным методам, находятся они в классе instance.DroidInstance
В комментариях к методам разработчики решили себя не утруждать, поэтому догадываться придется самим. Я напишу основные, остальное думаю вам не составит труда по названиям определить, имена большей части методов присвоены адекватные.


C#:
instance.DroidInstance.Action – выбор запуск, создание и  остановка устройства
instance.DroidInstance.App – действия с приложениями
instance.DroidInstance.AppiumDriver – получение объекта элемента
instance.DroidInstance.Input – свайпы, тачи, ввод текста
По поводу поиска элементов на экране, для этого есть 4 метода
instance.DroidInstance.AppiumDriver.FindElementById(); - по атрибуту resource-id
115293

instance.DroidInstance.AppiumDriver.FindElementByAccessibilityId();- по атрибуту content-desc
115292

instance.DroidInstance.AppiumDriver.FindElementsByClassName(); - по атрибуту class
115291

С поиском через xPath думаю вопросов быть не должно.


C# Кубики

А теперь напишем несколько кубиков. Для свайпа, тача, ввода текста и ожидания элемента.

C#:
public IAndroidElementAPI WaitElementByXPath(string xPath)
{
    IAndroidElementAPI element = null;
    try
    {
        element = instance.DroidInstance.AppiumDriver.FindElementByXPath(xPath);
    }
    catch (Exception ex)
    {
        throw new Exception("Не удалось осуществить инициализацию элемента для ожидания, проверьте xPath: " + ex.Message);
    }

    int counter = 0;

    while (element == null)
    {
        if (counter == 10) //Количество попыток для инициализации
        {
            throw new Exception("Элемент не появился: " + xPath);
        }
        project.SendInfoToLog("Ожидание элемента: " + xPath);
        element = instance.DroidInstance.AppiumDriver.FindElementByXPath(xPath);
        Thread.Sleep(3000); //Пауза между попытками в МС
        counter++;
    }

    Thread.Sleep(1000); //Пауза после нахождения элемента в МС, нужна для того что иногда элемент находится в дереве быстрее того как он появится на экране.
    return element; //Возвращаем инициализированный элемент.
}
C#:
public void ClickToElementByXpath(string xPath, int PauseAfterClickInSec) // В качестве параметров принимает xPath и паузу после клика в секундах
{
    Random rnd = new Random();
    IAndroidElementAPI Element = WaitElementByXPath(xPath); //Принимаем элемент из прошлого метода
    var elementLocation = Element.GetAttribute("bounds").Replace("][", "|").Replace("]", "").Replace("[", ""); //Получаем его координаты из свойства bounds

    //Раскладываем по переменным его координаты
    int x1 = Convert.ToInt32(elementLocation.Split('|')[0].Split(',')[0]);
    int x2 = Convert.ToInt32(elementLocation.Split('|')[1].Split(',')[0]);
    int y1 = Convert.ToInt32(elementLocation.Split('|')[0].Split(',')[1]);
    int y2 = Convert.ToInt32(elementLocation.Split('|')[1].Split(',')[1]);

    int randomX = rnd.Next(x1,x2); // Получаем рандомную точку между координатами x
    int randomY = rnd.Next(y1, y2); // Получаем рандомную точку между координатами y

    instance.DroidInstance.Input.Tap (randomX, randomY); //деламем клик

    project.SendInfoToLog("Сделали клик по элементу: " + xPath, true);
    Thread.Sleep(PauseAfterClickInSec * 1000);
}
C#:
public void SwipeUp()
{
    Random random = new Random();

    int height = Convert.ToInt32(Convert.ToDouble(project.Profile.DisplayHeight) * 0.87); //получаем и уменьшаем высоту экрана на 13% что бы не цеплять элементы интерфейса
    int width = project.Profile.DisplayWidth; // получаем ширину экрана

    int randomHeight = (height * random.Next(30, 40)) / 100; //Определяем размер поля для свайпа по y
    int randomWidth = (width * random.Next(10, 17)) / 100; Определяем размер поля для свайпа по x


    instance.DroidInstance.Input.Swipe
        (random.Next(width / 2 - randomWidth, width / 2 + randomWidth), random.Next(height / 2 + randomHeight, height / 2 + randomHeight),
         random.Next(width / 2 - randomWidth, width / 2 + randomWidth), random.Next(height / 2 - randomHeight, height / 2 - randomHeight),
         random.Next(1000, 2000));
}
C#:
public void SwipeDown()
{
    Random random = new Random();
    int height = Convert.ToInt32(Convert.ToDouble(project.Profile.DisplayHeight) * 0.87);
    int width = project.Profile.DisplayWidth;
    int randomHeight = (height * random.Next(30, 40)) / 100;
    int randomwidth = (width * random.Next(10, 17)) / 100;

    instance.DroidInstance.Input.Swipe
        (random.Next(width / 2 - randomwidth, width / 2 + randomwidth), random.Next(height / 2 - randomHeight, height / 2 - randomHeight),
         random.Next(width / 2 - randomwidth, width / 2 + randomwidth), random.Next(height / 2 + randomHeight, height / 2 + randomHeight), random.Next(1000, 2000));
}
C#:
public void SwipeSearchElementByXpath(string xpath)
{
    var element = instance.DroidInstance.AppiumDriver.FindElementByXPath(xpath); // инициализируем элемент
    Random random = new Random();

    int counter = 0;
    while (element == null) //Проверяем наличие элемента, если его нету то заходим в while
    {
        if (counter == 20) //Количество попыток свайпа
        {
            throw new Exception("Сделали 20 свайпов а элемент так и не появился");
        }
        SwipeUp(); // Делаем свайп
        element = instance.DroidInstance.AppiumDriver.FindElementByXPath(xpath); // Пробуем найти элемент
        Thread.Sleep(random.Next(500, 1000)); //Пауза между свайпами
        counter++;
    }

}
C#:
public void SendTextByXpath(string xPath, string text)
{
    Random random = new Random();
    SwipeSearchElementByXpath(xPath);//Ищем элемент
    Thread.Sleep(1000);
    ClickToElementByXpath(xPath,2);//Кликаем по нему
    instance.DroidInstance.Input.SendText(text, random.Next(100, 250)); // Вводим текст
    instance.DroidInstance.Input.SendKeyCode(KeyCode.KEYCODE_ENTER); //Нажимаем enter после ввода текста
}

Класс и методы для запуска машины через лок и семафор
C#:
public class StartMachine
{
    public static Semaphore SinhronizationStartingMachineSemaphore = new Semaphore(2, 2);//Статичный объект семафора  2,2 это то , сколько машин могут одновременно запускаться
    public static object SinhronizationStartingMachineObj = new object();//Статичный объект лока

    Instance instance;
    IZennoPosterProjectModel project;
    public StartMachine(Instance instance, IZennoPosterProjectModel project)
    {
        this.instance = instance;
        this.project = project;
    }

    public void StartLock()
    {
        lock (SinhronizationStartingMachineObj)
        {
            instance.DroidInstance.Action.Stop();
            instance.DroidInstance.Action.Start(true); // true значит что запускаем машину с применением настроек профиля, если не хотите их применять пропишите туда false
        }
    }

    public void StartSemaphore()
    {
        SinhronizationStartingMachineSemaphore.WaitOne(); // Запрашиваем разрешение на доступ.

        try
        {
            instance.DroidInstance.Action.Stop();
            instance.DroidInstance.Action.Start(true);
        }
        finally
        {
            SinhronizationStartingMachineSemaphore.Release(); // Освобождаем разрешение после выполнения работы.
        }
    }
}

Все эти методы добавлены в общий код шаблона который я прикрепил к статье.


ZennoDroid + VisualStudio

Ну это прям для тертых калачей)
Прямого подруба vs к zd как vs к zp нету, придется мальца повозиться.

Сначала нам надо создать проект либы в студии.
115277
115279

Затем в папке проекта вам надо найти файл ProjectName.csproj (лежит рядом с файлом sln)
115280
и открыть его с помощью блокнота, удалить содержимое и вставить такое.
XML:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net4.8</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<Reference Include="ZennoLab.CommandCenter">
<HintPath>$(ZennoDroidDllPath)\ZennoLab.CommandCenter.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="ZennoLab.Emulation">
<HintPath>$(ZennoDroidDllPath)\ZennoLab.Emulation.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="ZennoLab.InterfacesLibrary">
<HintPath>$(ZennoDroidDllPath)\ZennoLab.InterfacesLibrary.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="ZennoDroid.Interface">
<HintPath>$(ZennoDroidDllPath)\ZennoDroid.Interface.dll</HintPath>
</Reference>
</ItemGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<StartAction>Program</StartAction>
<StartProgram>$(ZennoDroidDllPath)\ZennoLab.CodeRunner.exe</StartProgram>
<StartArguments>50606 "$(MSBuildThisFileDirectory)bin\Debug\net4.8\$(MSBuildProjectName).dll" -sp "$(USER_HOME)\AppData\Roaming\ZennoLab\ZennoPoster\7" --run-external-dll</StartArguments>
</PropertyGroup>

</Project>

Создать класс Program, унаследовать им интерфейс IZennoExternalCode и реализовать его.
115281
В итоге получаем вот такое.

Метод Execute является у нас точкой входа. Тут мы уже можем развернуться как следует, подключить другие проекты, насоздавать пространств имен, классов, методов и прочей бесовщины). Крупный проект на пример может вот так выглядеть.
115282
Намного удобнее чем простыню делать в общем коде.

А теперь расскажу как это в проект подкинуть. Кубика VisualStudio как в зенопостере у нас нету. Но я как то копался в документации Zennodroid и нашел там один пример проекта в котором этот кубик откуда то был, в итоге я его просто методом копирования переношу в свои проекты, с вами я им тоже поделюсь в файлах к статье.
115283

В кубике мы уже просто указываем путь к dll нашей либы и запускаем его.

Практика

Ну а теперь давайте используя все полученные знания и напишем простенький шаблон для того что бы заработать нашу первую копеечку.
Для этого мы зарегаем кошелек монетки Neurai (XNA) и нападем с ним на кран.
Шаблон будет прикреплен к статье, код и кубики будут максимально прокомментированы.
115287

Папка с шабом оказалась слишком большой, так что пришлось заливать в облако https://disk.yandex.ru/d/SkzBRgTfh9W9Ew


БОНУС
Решение Yandex Smart Captcha через клики.


 
Тема статьи
Другое
Номер конкурса статей
Двадцатый конкурс статей

Для запуска проектов требуется программа ZennoPoster или ZennoDroid.
Это основное приложение, предназначенное для выполнения автоматизированных шаблонов действий (ботов).
Подробнее...

Для того чтобы запустить шаблон, откройте нужную программу. Нажмите кнопку «Добавить», и выберите файл проекта, который хотите запустить.
Подробнее о том, где и как выполняется проект.

Последнее редактирование модератором:

radv

Client
Регистрация
11.05.2015
Сообщения
3 788
Благодарностей
1 952
Баллы
113

Sherminator

Client
Регистрация
10.09.2021
Сообщения
1 261
Благодарностей
679
Баллы
113
У меня один старый образ мему весит уже 21 гб., а новый 4 гб.

Уменьшение размера машины ZennoDroid для хранения.
В подсчете веса машины я не считаю disk1 т.к он универсальный, в итоге новая машина без него 2 весит
Если не секрет, чего вы там на машине такого мутите что она до 21 гига разожралась?)
 

radv

Client
Регистрация
11.05.2015
Сообщения
3 788
Благодарностей
1 952
Баллы
113
Если не секрет, чего вы там на машине такого мутите что она до 21 гига разожралась?)
Да там просто тестовый образ, с разными приложениями для тестирования и отладки. Установил игру для автоматизации одним проектом. она скачала пару гигов, и доросла постепенно до 21. Понаблюдайте, если просто запускать мему, даже ничего нового не устанавливая, образ все равно будет расти.
 
  • Спасибо
Реакции: Sherminator

nester2021

Client
Регистрация
14.09.2022
Сообщения
8
Благодарностей
1
Баллы
3
Что за кран и сколько платит?
 
Регистрация
03.11.2019
Сообщения
16
Благодарностей
2
Баллы
3
Здравствуйте. Подскаижите как пути прописать для решения яндекс капчи? Такая ошибка при запуске проекта:
Тип Время Сообщение
09:43:06 Компиляция кода проекта Ошибка в действии "CS0006" "Metadata file 'C:\Program Files\ZennoLab\RU\ZennoDroid Pro\2.3.7.0\Progs\ExternalAssemblies\Newtonsoft.Json.dll' could not be found".
09:43:06 Компиляция кода проекта Ошибка в действии "CS0006" "Metadata file 'C:\Program Files\ZennoLab\RU\ZennoDroid Pro\2.3.7.0\Progs\ExternalAssemblies\YandexSmartCaptcha.dll' could not be found".
 

Sherminator

Client
Регистрация
10.09.2021
Сообщения
1 261
Благодарностей
679
Баллы
113
Здравствуйте. Подскаижите как пути прописать для решения яндекс капчи? Такая ошибка при запуске проекта:
Тип Время Сообщение
09:43:06 Компиляция кода проекта Ошибка в действии "CS0006" "Metadata file 'C:\Program Files\ZennoLab\RU\ZennoDroid Pro\2.3.7.0\Progs\ExternalAssemblies\Newtonsoft.Json.dll' could not be found".
09:43:06 Компиляция кода проекта Ошибка в действии "CS0006" "Metadata file 'C:\Program Files\ZennoLab\RU\ZennoDroid Pro\2.3.7.0\Progs\ExternalAssemblies\YandexSmartCaptcha.dll' could not be found".
Доброго времени суток, Вы видео смотрели? у вас файлы библиотек не добавлены в ExternalAssemblies. Я во второй половине видео подробно рассказываю как её подрубить
 
  • Спасибо
Реакции: Дмитрий00007

Sherminator

Client
Регистрация
10.09.2021
Сообщения
1 261
Благодарностей
679
Баллы
113

Demiz

Client
Регистрация
19.12.2017
Сообщения
187
Благодарностей
121
Баллы
43
Спасибо за статью, как по мне так шикарная! Вопрос есть: Когда ты работаешь со множества виртуальных машин, на каждую машину не нужно сохранять профиль, потом его загружать? Когда мы вначале сгенерировали новое устройство, потом его запустили с галочкой "Применять настройки профиля при запуске" и потом уже при работе или при импортировании этого устройства оно подгрузиться с нужными нам сгенерированными параметрами? Сам недавно работаю с дроидом, нужно масштабировать количество виртуальных машин и не хотелось чтобы они работали с 1 профилем
 

Sherminator

Client
Регистрация
10.09.2021
Сообщения
1 261
Благодарностей
679
Баллы
113
Спасибо за статью, как по мне так шикарная! Вопрос есть: Когда ты работаешь со множества виртуальных машин, на каждую машину не нужно сохранять профиль, потом его загружать? Когда мы вначале сгенерировали новое устройство, потом его запустили с галочкой "Применять настройки профиля при запуске" и потом уже при работе или при импортировании этого устройства оно подгрузиться с нужными нам сгенерированными параметрами? Сам недавно работаю с дроидом, нужно масштабировать количество виртуальных машин и не хотелось чтобы они работали с 1 профилем
Я вместе с архивом машины сохраняю и профиль, по идеи когда ты первый раз запускаешь машину с применением настроек профиля они сохраняются в эмуляторе, но я не рискую и поэтому каждый раз после работы пересохраняю профиль
 
  • Спасибо
Реакции: Lest и Demiz

Demiz

Client
Регистрация
19.12.2017
Сообщения
187
Благодарностей
121
Баллы
43
Я вместе с архивом машины сохраняю и профиль, по идеи когда ты первый раз запускаешь машину с применением настроек профиля они сохраняются в эмуляторе, но я не рискую и поэтому каждый раз после работы пересохраняю профиль
А когда тебе нужно взять машину в работу, профиль загружаешь после того, как запустил ее?
 

Sherminator

Client
Регистрация
10.09.2021
Сообщения
1 261
Благодарностей
679
Баллы
113
А когда тебе нужно взять машину в работу, профиль загружаешь после того, как запустил ее?
сначала загружаю профиль, потом запускаю машину с применением настроек профиля
 
  • Спасибо
Реакции: Demiz

Demiz

Client
Регистрация
19.12.2017
Сообщения
187
Благодарностей
121
Баллы
43
Подскажи по твоим наблюдениям какая сейчас наиболее стабильная версия андроида 7.1 или 9.0? Переключился на 7 после 9 и мне кажется стало гораздо легче запускаться и меньше лагов, но как в плане анонимности непонятно
 

Sherminator

Client
Регистрация
10.09.2021
Сообщения
1 261
Благодарностей
679
Баллы
113
Подскажи по твоим наблюдениям какая сейчас наиболее стабильная версия андроида 7.1 или 9.0? Переключился на 7 после 9 и мне кажется стало гораздо легче запускаться и меньше лагов, но как в плане анонимности непонятно
я на 9 работаю
 
  • Спасибо
Реакции: Demiz

artsmm

Client
Регистрация
03.10.2018
Сообщения
1 136
Благодарностей
196
Баллы
63
Привет. Как я могу пройти вниз по дереву с помощью xpath и получить кнопку именно у первого элемента?
116104


Я бы плясал от названия товара. Понимаю как на обычном постере это сделать, а на дроиде как?
 

artsmm

Client
Регистрация
03.10.2018
Сообщения
1 136
Благодарностей
196
Баллы
63
да, и еще вопрос: как сделать прокрутку до верха экрана на дроиде?
 

Sherminator

Client
Регистрация
10.09.2021
Сообщения
1 261
Благодарностей
679
Баллы
113
Привет. Как я могу пройти вниз по дереву с помощью xpath и получить кнопку именно у первого элемента?
Посмотреть вложение 116104

Я бы плясал от названия товара. Понимаю как на обычном постере это сделать, а на дроиде как?
Привет, с этими двумя моментами я ещё не сталкивался, поэтому подсказать не могу
 

Чешир

Client
Регистрация
27.06.2014
Сообщения
1 634
Благодарностей
963
Баллы
113
Классная статья, спасибо. А откуда лучше качать апк-шки приложух?
 

Sherminator

Client
Регистрация
10.09.2021
Сообщения
1 261
Благодарностей
679
Баллы
113
  • Спасибо
Реакции: Чешир

tootee

Client
Регистрация
17.01.2016
Сообщения
20
Благодарностей
4
Баллы
3
@Sherminator
Хорошая статья, спасибо! А сейчас с новой мему где образы цельные как вопросы решаете?
 

Sherminator

Client
Регистрация
10.09.2021
Сообщения
1 261
Благодарностей
679
Баллы
113

Кто просматривает тему: (Всего: 2, Пользователи: 0, Гости: 2)