Техническая статья | Пишем своё ZennoDroid API для работы с Yandex Browser

Dmitriy Ka

Client
Регистрация
03.05.2016
Сообщения
712
Благодарностей
450
Баллы
63
Всем привет, с вами Дмитрий.

В данной статье я поделюсь своими наработками по автоматизации работы с Yandex Browser для ZennoDroid. Здесь вы найдете мое решение по основным методам API, для автоматизации работы приложения Яндекс Браузер. Благодаря API-методам, вы сможете выполнять сложную логику работы всего в одну строчку кода.

А еще кто не имеет большого опыта программирования на C#, хорошие новости. Вы также сможете использовать данные методы, вставляя всего лишь одну строчку кода и получая результат в переменную для дальнейшей работы в шаблоне.

Так же на примере моей работы, Вы сможете писать свои методы API для других приложений или адоптировать под свои задачи дополнительные методы для работы с Yandex Browser.

API написано для приложения Яндекс Браузер - с нейросетями (com.yandex.browser). Работает как с эмуляторами, так и на реальных устройствах (ZDP \ ZDE).

К данной статье прикрепляю шаблон с примерами работы методов. Что бы Вы легко смогли опробовать их.

Установка API.
Для работы API методов вам нужно скопировать код ниже и вставить его в "Общий код" ZDP \ ZDE.
125290


ZD API Yandex Browser:
public static class ZInstance
{
    public static Yandex Yandex(this Instance instance) => new Yandex(instance);
}

public class Yandex
{
    private IDroidInstanceAPI _droid;
    private Random _r = new Random();

    public readonly string PACK = "com.yandex.browser";
    private readonly string LogEx = "Yandex > ";

    /// <summary>
    /// Ширина экрана.
    /// </summary>
    private int SWidth { get; set; }

    /// <summary>
    /// Высота экрана.
    /// </summary>
    private int SHeight { get; set; }

    public Yandex(Instance instance)
    {
        _droid = instance.DroidInstance;
        ScreenSize();
    }

    /// <summary>
    /// Установлено ли приложение Yandex.
    /// </summary>
    /// <returns></returns>
    public bool IsInstal()
    {
        return _droid.App.IsInstalled(PACK);
    }

    /// <summary>
    /// Проверка открытого Yandex
    /// </summary>
    /// <returns></returns>
    public bool IsOpen()
    {
        if (_droid.App.Top != PACK)
        {
            return false;
        }

        return true;
    }

    /// <summary>
    /// Открываем Yandex.
    /// </summary>
    /// <param name="sleep"></param>
    /// <returns></returns>
    public Yandex Open(int sleep = 500)
    {
        _droid.App.Open(PACK);
        Thread.Sleep(sleep);

        return this;
    }

    /// <summary>
    /// Открываем ссылку в Yandex.
    /// </summary>
    /// <returns></returns>
    public Yandex OpenUrl(string url, int sleep = 1000)
    {
        _droid.App.OpenUrl(url, PACK);
        Thread.Sleep(sleep);

        return this;
    }

    /// <summary>
    /// Ручной ввод 'поиск или сайт'.
    /// </summary>
    /// <param name="value"></param>
    /// <param name="sleep"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public bool EnterValue(string value, int sleep = 1000)
    {
        IAndroidElementAPI de;

        try
        {
            // Кликаем на поле.
            de = _droid.AppiumDriver.FindElementByXPath("//*[@text='поиск или сайт']");
            if (de == null)
            {
                de = _droid.AppiumDriver.FindElementById("com.yandex.browser:id/bro_omnibar_address_title_text");
                if (de == null)
                {
                    SwipeDown();
                    Thread.Sleep(1000);
                    de = _droid.AppiumDriver.FindElementById("com.yandex.browser:id/bro_omnibar_address_title_text");
                }
            }

            if (de != null)
            {
                de.Click();
                Thread.Sleep(1000);
            }
            else return false;

            // очишаем если что-то вбито.
            de = _droid.AppiumDriver.FindElementById("com.yandex.browser:id/suggest_omnibox_clear_button");
            if (de != null)
            {
                de.Click();
                Thread.Sleep(300);
            }

            // вводим значение.
            _droid.Input.SendText(value, 150);
            Thread.Sleep(300);

            de = _droid.AppiumDriver.FindElementById("com.yandex.browser:id/suggest_omnibox_action_button");
            if (de != null)
            {
                de.Click();
            }
            else return false;

            Thread.Sleep(sleep);

        }
        catch
        {
            return false;
        }

        return true;
    }

    /// <summary>
    /// Проверка отладки по USB, если нет включает.
    /// </summary>
    public void UsbDebag()
    {
        try
        {
            Open(1000);
            GetHtml();
        }
        catch
        {
            Open(1000);
        }
    }

    /// <summary>
    /// Проверка существует ли WebView.
    /// </summary>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public bool IsWebView()
    {
        try
        {
            var webViewElement = _droid.AppiumDriver.FindElementByClassName("android.webkit.WebView");

            if (webViewElement != null)
            {
                return true;
            }

            return false;
        }
        catch (Exception ex)
        {
            throw new Exception(LogEx + "IsWebView: " + ex.Message);
        }
    }

    /// <summary>
    /// Востанваливаем WebView
    /// </summary>
    public void ReturnWebView()
    {
        _droid.Screen.RefreshScreen();
    }

    /// <summary>
    /// Выполнить JavaScript команду.
    /// </summary>
    /// <returns></returns>
    public string JS(string script)
    {
        try
        {
            return _droid.WebView.EvaluateScript(script);
        }
        catch (Exception ex)
        {
            throw new Exception(LogEx + "JS(): " + ex.Message);
        }
    }

    /// <summary>
    /// Получаем верстку страницы.
    /// </summary>
    /// <returns></returns>
    public string GetHtml()
    {
        try
        {
            return _droid.WebView.EvaluateScript("return document.documentElement.innerHTML");
        }
        catch (Exception ex)
        {
            throw new Exception(LogEx + "GetHtml(): " + ex.Message);
        }
    }

    /// <summary>
    /// Закрываем все вкладки браузера Yandex.
    /// </summary>
    public Yandex CloseAllTabs()
    {
        TabSwitcherButton();

        try
        {
            // Кнопка Закрыть все вкладки
            var de = _droid.AppiumDriver.FindElementById("com.yandex.browser:id/bro_delete_button");
            if (de != null)
            {
                de.Click();
                Thread.Sleep(500);
            }

            // Кнопка подтвердить закрыть все вкладки
            de = _droid.AppiumDriver.FindElementById("com.yandex.browser:id/bro_popup_action_button_stub");
            if (de != null)
            {
                de.Click();
                Thread.Sleep(500);
            }

            return this;
        }
        catch (Exception ex)
        {
            throw new Exception(LogEx + "CloseAllTabs:" + ex.Message);
        }
    }

    /// <summary>
    /// Получить количество вкладок Yandex
    /// </summary>
    public int CountTabs()
    {
        // Работает без открытия вкладок!
        try
        {
            int count = 0;
            var info = _droid.AppiumDriver.FindElementById("com.yandex.browser:id/bro_omnibox_button_tabswitcher");
            if (info != null)
            {
                var match = Regex.Match(info.GetAttribute("content-desc"), @"\d+");

                if (match.Success)
                {
                    count = int.Parse(match.Value);
                }
            }

            return count;
        }
        catch
        {
            return 0;
        }
    }

    /// <summary>
    /// Первый запуск Yandex (после очистки).
    /// </summary>
    /// <param name="sleep"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public Yandex FirstStart(int sleep = 1000)
    {
        string text;
        IAndroidElementAPI de;

        try
        {
            text = "Начать работу";
            de = _droid.AppiumDriver.FindElementByXPath($"//*[@text='{text}']");
            if (de != null)
            {
                de.Click();
                Thread.Sleep(500);
            }

            while (true)
            {
                text = "Продолжить";
                de = _droid.AppiumDriver.FindElementByXPath($"//*[@text='{text}']");
                if (de != null)
                {
                    de.Click();
                    Thread.Sleep(500);
                }
                else break;
            }

            text = "Продолжить без входа";
            de = _droid.AppiumDriver.FindElementByXPath($"//*[@text='{text}']");
            if (de != null)
            {
                de.Click();
                Thread.Sleep(1000);
            }

            text = "Пропустить";
            de = _droid.AppiumDriver.FindElementByXPath($"//*[@text='{text}']");
            if (de != null)
            {
                de.Click();
                Thread.Sleep(500);
            }

            text = "Не надо";
            de = _droid.AppiumDriver.FindElementByXPath($"//*[@text='{text}']");
            if (de != null)
            {
                de.Click();
                Thread.Sleep(500);
            }

            Thread.Sleep(sleep);

            return this;
        }
        catch (Exception ex)
        {
            throw new Exception(LogEx + "FirstStart:" + ex.Message);
        }

    }

    /// <summary>
    /// Проверка загрузки страницы через ProgressBar.
    /// </summary>
    /// <param name="countCheck"></param>
    /// <param name="sleep"></param>
    /// <returns></returns>
    public bool IsProgressBar(int countCheck, int sleep = 5000)
    {
        try
        {
            for (int i = 0; i < countCheck; i++)
            {
                var el = _droid.AppiumDriver.FindElementByClassName("android.widget.ProgressBar");
                if (el != null)
                {
                    Thread.Sleep(sleep);
                }
                else
                {
                    return false;
                }
            }

            return true;
        }
        catch (Exception ex)
        {
            throw new Exception(LogEx + "IsProgressBar:" + ex.Message);
        }
    }

    /// <summary>
    /// Закрываем Яндекс попапы.
    /// </summary>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public bool ClosePopup()
    {
        try
        {
            bool isCloce = false;

            var contentDesc = new[] {
            "Закрыть диалоговое окно",
            };

            foreach (var text in contentDesc)
            {
                var de = _droid.AppiumDriver.FindElementByXPath($"//*[@content-desc='{text}']");
                if (de != null)
                {
                    de.Click();
                    isCloce = true;
                }
            }

            var texts = new[] {
                "Закрыть диалоговое окно",
                "Не надо"
            };

            foreach (var text in texts)
            {
                var de = _droid.AppiumDriver.FindElementByXPath($"//*[@text='{text}']");
                if (de != null)
                {
                    de.Click();
                    isCloce = true;
                }
            }

            return isCloce;
        }
        catch (Exception ex)
        {
            throw new Exception(LogEx + "YandexLowerPopup:" + ex.Message);
        }

    }

    /// <summary>
    /// Получаем куки Yandex.
    /// </summary>
    /// <returns></returns>
    public string GetCookies()
    {
        return _droid.App.GetCookie(PACK);
    }

    /// <summary>
    /// Сделать выгрузку данных Yandex
    /// </summary>
    /// <param name="pathSave"></param>
    /// <returns></returns>
    public Yandex Backup(string pathSave)
    {
        _droid.App.BackupAppData(PACK, pathSave);

        return this;
    }

    /// <summary>
    /// Загрузать данные Yandex из Backup
    /// </summary>
    /// <param name="pathSave"></param>
    /// <returns></returns>
    public Yandex Restore(string pathSave)
    {
        _droid.App.RestoreAppData(PACK, pathSave);

        return this;
    }

    /// <summary>
    /// Очашаем данные Yandex.
    /// </summary>
    /// <param name="onlyCache"></param>
    /// <returns></returns>
    public Yandex Clear(bool onlyCache = false)
    {
        if (onlyCache)
        {
            _droid.App.CleanCache(PACK);

            return this;
        }

        _droid.App.Clean(PACK);

        return this;
    }

    /// <summary>
    /// Кнопка открыть вкладки
    /// </summary>
    private Yandex TabSwitcherButton()
    {
        try
        {
            var de = _droid.AppiumDriver.FindElementById("com.yandex.browser:id/bro_omnibox_button_tabswitcher");
            if (de != null)
            {
                de.Click();
            }

            return this;
        }
        catch (Exception ex)
        {
            throw new Exception(LogEx + "TabSwitcherButton:" + ex.Message);
        }

    }

    /// <summary>
    /// Свайп вниз.
    /// </summary>
    private void SwipeDown()
    {
        // Вычисления для начальной и конечной точек
        Point start, end;
        Points(out start, out end);

        //Задержка
        _droid.Input.SwipeCurved(end.X, end.Y, start.X, start.Y, 70);
    }

    private void Points(out Point start, out Point end)
    {
        int height = Percent(SHeight, 86);
        int width = SWidth;

        int randomHeight = Percent(height, _r.Next(10, 15));
        int randomWidth = Percent(width, _r.Next(2, 6));

        // Вычисления для начальной и конечной точек
        int wS = Percent(width, 70);
        int wE = Percent(width, 72);

        start = new Point()
        {
            X = _r.Next(wS - randomWidth, wS + randomWidth),
            Y = Percent(height, 82) + randomHeight
        };

        end = new Point()
        {
            X = _r.Next(wE - randomWidth, wE + randomWidth),
            Y = Percent(height, 70) - randomHeight
        };
    }
    private int Percent(int value, int percent)
    {
        return value * percent / 100;
    }

    private void ScreenSize()
    {
        try
        {
            string xml = "";

            for (int i = 0; i < 3; i++)
            {
                xml = _droid.Hierarchy.GetLayout();
                if (xml.Length > 0)
                {
                    break;
                }

                Thread.Sleep(2000);
            }

            if (string.IsNullOrEmpty(xml))
            {
                throw new Exception(LogEx + "ScreenSize: Не могу получить XML экрана");
            }

            SWidth = int.Parse(Regex.Match(xml, "(?<=width=\")[\\w\\W]*?(?=\")").Value);
            SHeight = int.Parse(Regex.Match(xml, "(?<=height=\")[\\w\\W]*?(?=\")").Value);

            if (SWidth == 0 || SHeight == 0)
            {
                throw new Exception(LogEx + "ScreenSize: Не смогли получить данные экрана");
            }
        }
        catch (Exception ex)
        {
            throw new Exception(LogEx + "ScreenSize: " + ex.Message);
        }
    }
}
Как обрушаться к методам.
Методы реализованы через метод расширения instance, поэтому чтобы к ним обратиться достаточно прописать instance.Yandex() и через . выбрать нужный вам метод.
Например: instance.Yandex().Open()

Описание API методов.

bool IsInstal()
- метод проверяет, установлено ли приложение Yandex Browser. Возвращает True если установлено и False если нет.
вызываем как instance.Yandex().IsInstal();

bool IsOpen() - метод проверяет запущен ли ЯБ. Возвращает True если запущен и False если нет
вызываем как instance.Yandex().IsOpen();

Yandex Open(int sleep = 500) - метод который открывает ЯБ (например если метод IsOpen() вернул False, значит ЯБ не запушен и можно его запустить).
*Имеет задержку по умолчанию 0.5 секунд, можно менять.
вызываем как instance.Yandex().Open();

Yandex OpenUrl(string url, int sleep = 1000) - метод открывает ЯБ и сразу нужный сайт, который передадим в url (важно url c http).
*Имеет задержку по умолчанию 1 секунда, можно менять.
вызываем как instance.Yandex().OpenUrl("https://ya.ru/");

bool EnterValue(string value, int sleep = 1000) - метод ввода значения в поле 'поиск или сайт'. В значение value мы можем передавать, как поисковый запрос, так и сразу сайт. *Имеет задержку по умолчанию 1 секунда, можно менять.
вызываем как instance.Yandex().EnterValue("новости");

void UsbDebag() - метод который включает отладку по USB для ЯБ, нужно, чтобы была возможность исполнять JS скрипты.
вызываем как instance.Yandex().UsbDebag();

bool IsWebView() - метод который проверяет наличие WebView на странице (оно иногда отваливается). WebView важно, оно хранит основные элементы страницы для взаимодействия.
вызываем как instance.Yandex().IsWebView();

void ReturnWebView() - метод который восстанавливает WebView. Запускам если оно отвалилось, чтобы шаблон мог продолжить работать.
вызываем как instance.Yandex().ReturnWebView();

string JS(string script) - метод который позволяет исполнять JS команды (перезагрузить страницу, понять позицию скролла и очень много еще чего).
вызываем как instance.Yandex().JS("return document.documentElement.innerHTML");

string GetHtml() - метод получения Html страницы (очень полезный :-) ).
вызываем как instance.Yandex().GetHtml();

Yandex CloseAllTabs() - метод закрытия всех вкладок ЯБ.
вызываем как instance.Yandex().CloseAllTabs();

int CountTabs() - метод который получает количество вкладок.
вызываем как var count = instance.Yandex().CountTabs();

Yandex FirstStart(int sleep = 1000) - метод Первый запуск. Закрывает все всплывающие окна ЯБ, когда очистили браузер или только установили.
*Имеет задержку по умолчанию 1 секунда, можно менять.
вызываем как instance.Yandex().FirstStart();

bool IsProgressBar(int countCheck, int sleep = 5000) - метод проверки загрузки страницы (спасибо за наводку @Sherminator ). Проверят загрузилась ли страница, если нет то ждет 5 сек и еще раз проверят. Количество попыток для проверки передаем с методом в countCheck. Если в течения цикла все равно будет загрузка вернет False.
вызываем как instance.Yandex().IsProgressBar(5);

bool ClosePopup() - метод закрытия Попапов ЯБ. Закрывает всплывающие окна ЯБ.
вызываем как instance.Yandex().ClosePopup();

string GetCookies() - метод получения куков ЯБ.
вызываем как instance.Yandex().GetCookies();

Yandex Backup(string pathSave) - метод сохранения Backup приложения ЯБ (ZDE версия 10+ позволяет сохранять данные на устройстве). Указываем путь куда сохранить данные бэкапа, для хранения на устройстве "/sdcard/Download/".
вызываем как instance.Yandex().Backup("/sdcard/Download/Backups/1");

Yandex Restore(string pathSave) - метод загрузки Backup приложения ЯБ. Указываем полный путь с расширением ".tar.gz"
вызываем как instance.Yandex().Restore("/sdcard/Download/Backups/1.tar.gz");

Yandex Clear(bool onlyCache = false) - метод очистки данных ЯБ. Можем очистить только кеш, для этого передаем в метод true.
вызываем как
instance.Yandex().Clear();
instance.Yandex().Clear(true);

Так же отдельно записал небольшое видео, как создавать свои API методы и как подключить ZennoDroid к VisualStudio


#####################
Мой Телеграм Канал
Мой Youtube Канал

Поддержка автора: Донат
USDT TRC20: TBbnjJGwHEeKP5KEr7FNhsBmhR6V1XKds1
#####################

У кого проблемы с YouTube, продублировал видео в ВК
 

Вложения

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

radv

Client
Регистрация
11.05.2015
Сообщения
3 776
Благодарностей
1 942
Баллы
113
Спасибо за примеры и проект для VisualStudio
 
  • Спасибо
Реакции: Dmitriy Ka

seodamage

Client
Регистрация
08.09.2014
Сообщения
220
Благодарностей
65
Баллы
28
очень вовремя и есть куда применить, большое спасибо!
 

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