Android клиент для rutracker: обходим блокировку при помощи Google Compression proxy

    Полагаю, что все пользователя хабра так или иначе нашли способ попадать на рутрекер, но порой бывает лень включать свой тор, прокси, впн или что либо ещё. Мне вот стало лень, и поэтому я решил написать свой маленький клиент. Для обхода блокировок я решил использовать google compression proxy. Интересная, хорошая и полезная штука — странно, что по её поводу на хабре не было статей. Забегая вперёд, сразу скажу, что всё получилось, и работающую версию можно попробовать на своём девайсе. Однако в процессе возникло много всяких интересных нюансов, которые любопытны несколько больше, чем само приложение. Итак, начнём!


    Google Compression proxy


    Чтобы не повторять гугловые мануалы (все ссылки вы можете найти в конце статьи), просто скажу, что этот прокси сервер позволяет вашему Google Chrome значительно уменьшать количество воспринимаемого трафика за счёт его сжатия серверами Google. Работать прокси умеет по HTTP и по HTTPS. В первом случае используется адрес compress.googlezip.net, во втором — proxy.googlezip.net. Интересно, что для прокси требуется свой заголовок. В официальной документации его нет, однако можно найти исходники от гугла и немного в них покопаться. Выглядят они вот так (ссылка на самый интересный файл, размещено уже у меня на гихабе, поскольку в официальном репозитории на google code уже ничего посмотреть нельзя).
    Оттуда получаем такое добро:
    var authHeader = function() {
    	var authValue = 'ac4500dd3b7579186c1b0620614fdb1f7d61f944';
    	var timestamp = Date.now().toString().substring(0, 10);
    	var chromeVersion = navigator.appVersion.match(/Chrome\/(\d+)\.(\d+)\.(\d+)\.(\d+)/);
    	return {
    		name: 'Chrome-Proxy',
    		value: 'ps=' + timestamp + '-' + Math.floor(Math.random() * 1000000000) + '-' + Math.floor(Math.random() * 1000000000) + '-' + Math.floor(Math.random() * 1000000000) + ', sid=' + MD5(timestamp + authValue + timestamp) + ', b=' + chromeVersion[3] + ', p=' + chromeVersion[4] + ', c=win'
    	};
    };
    


    Всё довольно очевидно, но
    можно остановиться подробнее.
    Для каждого запроса должен присутствовать заголовок Chrome-Proxy.
    В нём должна быть следующая строка:
     ps=<timestamp>-<num1>-<num2>-<num3>, sid=<md5 string>, b=<build>, p=<patch>, c=<platform>
    

    где:

    timestamp: время в linux timestamp
    num1, num2, num3: некие случайные числа, которые можно поставить в 0
    md5 string: md5 хэш строки авторизации
    auth string:
    "<timestamp>" + "<auth key>" + "<timestamp>"

    auth key: ac4500dd3b7579186c1b0620614fdb1f7d61f944 — просто некий ключ… Один на всех, и все на одного.
    build: номер билда хрома — например, 2214
    patch: номер патча хрома — например, 115
    platform: платформа — например, «win»
    В качестве полного примера можно привести такой заголовок:
    Chrome-Proxy: ps=1439961190-0-0-0, sid=9fb96126616582c4be88ab7fe26ef593, b=2214, p=115, c=win


    Как ни странно и не смешно, можно использовать эту самую строку при любом количестве запросов без всяких изменений… Например, на этом основано расширение для Firefox, которое занимается пересжатием трафика. Видимо, просто делалась защита от ленивого дурака.
    Однако, честным вариантом будет переписать это на Java так:
        public static String[] authHeader() {
            String[] result = new String[2];
            result[0] = "Chrome-Proxy";
            String authValue = "ac4500dd3b7579186c1b0620614fdb1f7d61f944";
            String timestamp = Long.toString(System.currentTimeMillis()).substring(0, 10);
            String[] chromeVersion = {"49", "0", "2623", "87"};
            String sid = (timestamp + authValue + timestamp);
            sid = Utils.md5(sid);
            result[1] = "ps=" + timestamp + "-" + Integer.toString((int) (Math.random() * 1000000000)) + "-" + Integer.toString((int) (Math.random() * 1000000000)) + "-" + Integer.toString((int) (Math.random() * 1000000000)) + ", sid=" + sid + ", b=" + chromeVersion[2] + ", p=" + chromeVersion[3] + ", c=win";
            return result;
        }
    


    Далее надо выбрать, какой именно вариант для проксирования мы выбираем. Мой провайдер суров, и блокирует запросы, если они идут по HTTP через гугловую проксю, так что пришлось идти правильным путём через SSL.

    WebView через SSL


    Чтобы не идти долгим и печальным путём написания клиента с нуля, я решил «просто» показывать всё как есть через стандартный WebView, благо ранее уже писал простое-клиент, которое делает примерно то же самое, и шустро работает даже на тяжёлом веб сайте. Кажется — работы на полчаса. Как же я ошибался… Если посмотреть решения по проксированию WebView в интернете, то становится очень грустно — все делают примерно так:

    public static void setKitKatWebViewProxy(Context appContext, String host, int port, String exclusionList) {
        Properties properties = System.getProperties();
        properties.setProperty("http.proxyHost", host);
        properties.setProperty("http.proxyPort", port + "");
        properties.setProperty("https.proxyHost", host);
        properties.setProperty("https.proxyPort", port + "");
        properties.setProperty("http.nonProxyHosts", exclusionList);
        properties.setProperty("https.nonProxyHosts", exclusionList);
    /// ... such much shit
    }
    

    Оставшуюся часть намеренно опустил — там идёт ещё около сотни строк с условиями по версии андроида и жутким шаманством. При этом у многих это всё равно не работает, плюс есть проблемы с переключением режима проксирования — и её «решают» путём установки Thread.Sleep(1000) между операциями. Хотя я не являюсь Java разработчиком, а просто иногда балуюсь, мне поплохело. Здравый смысл подсказал мне, что нужно перехватывать запросы из Webview (для этого у WebViewClient есть чудесная функция shouldInterceptRequest), и далее самому заниматься проксированием. Это у меня даже вполне получилось:
      Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("compress.googlezip.net", 80));
      HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(proxy);
    


    Всё отлично, всё работает! Только одна проблема. Как заметили внимательные читатели, в параметрах функции указан 80ый порт. По довольно смешной причине. А именно — потому что HttpURLConnection не умеет работать с HTTPS проксями. Совсем. Никак. У меня ушло куча времени, чтобы понять, что всё настолько плохо, и что нельзя сделать HTTPS прокси ни через HttpURLConnection, ни через популярный okHttp. Я немного призадумался, затем решительным жестом отмёл все доводы Google о том, что библиотеки Apache не подходят для Android, стряхнул пыль с проверенных jar'ов и решительно подключил их к проекту. И всё получилось! Пятый и шестой андроид на ура восприняли такой ужасный проступок. Если кто-то знает, как можно было решить проблему без использования библиотек Apache — расскажите. Конечно, можно было бы сделать всё на сокетах, но это довольно печально.

    Итак, мы наконец смогли отобразить главную страницу рутрекера. Казалось бы, победа близко. Как же я ошибался.

    Реклама


    Практически с первой попытки отладки я столкнулся с тем, что всё чудовищно тормозит. Причина довольно очевидна — безумное количество рекламы всевозможных видов. Мне очень не хотелось с ней что-то делать — все мы знаем положение рутрекера, и чувакам явно нужно много золота для защиты от DDOS'a и родного государства — но с рекламой приложением было пользоваться вообще нереально. Правильным решением было бы находить её и вырезать из тела страницы, но более быстрым для реализации подходом было просто порезать её по хостам:

    довольно очевидный код
        public static boolean is_adv(Uri url) {
            String[] adv_hosts = {"marketgid.com", "adriver.ru", "thisclick.network", "hghit.com",
                    "onedmp.com", "acint.net", "yadro.ru", "tovarro.com", "marketgid.com", "rtb.com", "adx1.com",
                    "directadvert.ru", "rambler.ru"};
            String[] adv_paths = {"brand", "iframe"};
            String host = url.getHost();
            for (String item : adv_hosts) {
                if (StringUtils.containsIgnoreCase(host, item)) {
                    return true;
                }
            }
            if (StringUtils.containsIgnoreCase(url.getHost(), "rutracker.org")) {
                String path = url.getPath();
                for (String item : adv_paths) {
                    {
                        if (StringUtils.containsIgnoreCase(path, item)) {
                            return true;
                        }
                    }
                }
            }
            return false;
        }
    



    И после этого мы просто обрубаем её получение:
            if (Utils.is_adv(url)) {
                Log.d("WebView", "Not fetching advertisment");
                return new WebResourceResponse("text/javascript", "UTF-8", null);
            }
    

    Задним умом я только что подумал, что возможно было бы проще сделать список разрешённых хостов… Но этим самым умом все сильны.
    Теперь приложение стало работать не то что с приемлимой, а с очень бодрой и приятной скоростью. Если владельцев рутрекера это огорчит, то блокировку уберу — но скорее всего вместе с приложением. С чудовищными тормозами в нём просто не будет смысла.

    Отправка форм


    Довольно откинувшись на стул, я обнаружил… Что не работает авторизация. Что было на самом деле весьма очевидно — поскольку в перехватываемом мной и передаваемом далее запросе я не отправлял данные, которые должны уйти в POST. Казалось бы, пара минут — и всё будет хорошо. Как же я ошибался…
    Выяснилось, что способов перехватить POST из WebView нету. Совсем. Никак. Лучшие рекомендованные практики — внедрять в страницу свой javascript и вызывать из него специальные Java методы. Или переводить сервер на GET запросы. От первого варианта мне несколько поплохело, а второй недоступен по понятным причинам. Да и был бы некорректен. Почесав голову и попробовав отловить POST ещё в нескольких местах, я пришёл к выводу, что нормального решения всё же нет. В результате сделал решение смешное. А именно — при получении страницы менять метод всех форм с POST на GET. А после этого при следующем обращении конвертировать переданные в адресной строке параметры в тело POST запроса. Звучит ужасно, но всё не так плохо, если у вас нет адресной строки, в которой можно опозориться, больших переменных или файлов для передачи. Хотя нет, вру конечно. Всё очень плохо, но другого адекватного пути я не нашёл.
    довольно очевидный код
        public static UrlEncodedFormEntity get2post(Uri url) {
            Set<String> params = url.getQueryParameterNames();
            if (params.isEmpty())
                return null;
    
            List<NameValuePair> paramsArray = new ArrayList<>();
    
            for (String name : params) {
                Log.d("Utils", "converting parameter " + name + " to post");
                paramsArray.add(new BasicNameValuePair(name, url.getQueryParameter(name)));
            }
            try {
                return new UrlEncodedFormEntity(paramsArray, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            return null;
        }
    
    



    Где мои куки, чувак?


    Когда я в очередной раз откинулся на спинку кресла после успешно пройденной авторизации и кликнул следующую ссылку, я обнаружил, что авторизация умирает на следующей странице. Что в общем тоже довольно логично, поскольку никто волшебно куками не управляет, а посылаем мы все заголовки вручную. Но здесь я в кои-то веки не ошибся в том, что
    Скрытый текст
                if (Utils.is_login_form(url)) {
    
                    Header[] all = response.getAllHeaders();
                    for (Header header1 : all) {
                        Log.d("WebView", "LOGIN HEADER: " + header1.getName() + " : " + header1.getValue());
    
                    }
                    Header[] cookies = response.getHeaders("set-cookie");
                    if (cookies.length > 0) {
                        String val = cookies[0].getValue();
                        val = val.substring(0, val.indexOf(";"));
                        authCookie = val.trim();
                        CookieManager.put(MainContext, authCookie);
                        Log.d("WebView", "=== Auth cookie: ==='" + val + "'");
                        //redirect does not work o_O
                        String msgText = "<script>window.location = \"http://rutracker.org/forum/index.php\"</script>";
                        ByteArrayInputStream msgStream = new ByteArrayInputStream(msgText.getBytes("UTF-8"));
                        return new WebResourceResponse("text/html", "UTF-8", msgStream);
    
                    }
                }
    


    Правда, внимательный читатель обнаружит, что там идёт какая-то странная переадресация яваскриптом. Да, всё так. В ответе должен был быть 302 заголовок авторизации, но почему-то его никуда не приходило. В результате я оказывался на странице форума по некорректному адресу с доменом login.rutracker.org — всё работало, но, поскольку ссылки везде относительные, при следующем же клике наступал облом. Кстати, здесь же можно заметить, что пользовательскую куку мы бережно сохраняем, чтобы не пришлось потом заново авторизоваться.

    Теперь-то всё?!


    Именно с этим вопросом я в который раз открывал страничку, уже уверенный, что ничего не упустил. Как же я… В общем, можно было свободно искать через нативный поиск или через гугловый без авторизации, можно было смотреть любую тему, нельзя было только одно… Скачать торрент. Поскольку по нажатию ссылок ничего хорошего не происходит. Но в этот раз всё тоже было несложно — в интерфейс добавилась программная менюшка с кнопочкой Share, которая позволяет отправить куда угодно Magnet ссылку. Было бы удобнее кидать ссылку на торрент файл, но он у вас явно будет блокирован. Конечно, можно было бы скачивать торрент файл и передавать его через шаринг — но это как-нибудь в другой раз.

    Результат


    Можно посмотреть по скринам — главная страница и расшаривание magnet ссылки из топика.

    Осталось только опубликовать


    На основании тех странных android приложений, которые я выкладывал раньше, у меня сложилось ощущение, что они пропускают вообще всё. Так что я с лёгким сердцем отправил приложение на публикацию и сел писать статью. Обычно приложение появлялось на google play в течении пары часов, так что времени как раз хватало. К сожалению, в этот раз прошло 8 часов. И в ответ пришло
    вот такое письмо.
    After review, Rutracker free — unofficial, ru.jehy.proxy_rutracker, has been suspended and removed from Google Play as a policy strike because it violates the impersonation policy.
    Next Steps
    1. Read through the Impersonation article for more details and examples of policy violations.
    2. Make sure your app is compliant with the Impersonation and Intellectual Property policy and all other policies listed in the Developer Program Policies. Remember additional enforcement could occur if there are further policy issues with your apps.
    3. Sign in to your Developer Console and submit the policy compliant app using a new package name and a new app name.

    What if I have permission to use the content?

    Contact our support team to provide a justification for its use. Justification may include providing proof that you are authorized to use the content in your app or some other legal justification.Additional suspensions of any nature may result in the termination of your developer account, and investigation and possible termination of related Google accounts. If your account is terminated, payments will cease and Google may recover the proceeds of any past sales and/or the cost of any associated fees (such as chargebacks and transaction fees) from you.If you’ve reviewed the policy and feel this suspension may have been in error,please reach out to our policy support team. One of my colleagues will get back to you within 2 business days.


    Не совсем понятно, кто кого имперсонифицировал, но у меня было три варианта, что же не понравилось Google:
    1. Что я взял откуда-то иконки;
    2. Что я упомянул в комментариях, что приложение работает через google compression proxy;
    3. Что в качестве банеров я использовал варианты смешных логотипов рутрекера с нового конкурса;

    Конечно, в любом случае довольно неприятно, что нужно зачем-то переименовывать pakage и закачивать его заново. Да тебя ещё и предупреждают, что «я тебя запомнил, и ещё раз так сделаешь — забаню». Ну как-то по гопнически. Не ожидал, прям обидно.
    Из упомянутых выше вариантов я решил, что скорее всего виноват второй — упоминание Google всуе. Ну ладно, как скажете — не стал писать, как работает приложение. Просто «приложение с проксированием, которое позволяет обходить блокировку rutracker.org». Ну и заодно поставил кривые нарисованные за пять минут иконки и аналогичные банеры. И что вы думаете — мои усилия были вознаграждены! Дальше мне пришёл
    следующий ответ.
    After review, Rutracker free, ru.jehy.rutracker_free, has been suspended and removed from Google Play as a policy strike because it violates the webviews and affiliate spam policy.

    Next Steps

    Read through the Webviews and Affiliate Spam article for more details and examples of policy violations.
    Make sure your app is compliant with the Spam policy and all other policies listed in the Developer Program Policies. Remember that additional enforcement could occur if there are further policy issues with your apps.
    If it’s possible to bring your app into compliance, you can sign in to your Developer Console and submit the policy compliant app using a new package name and a new app name.


    В общем, меня обвинили в том, что не то приложение только реферральные ссылки передаёт, то ли ничего кроме вебвьюва не делает. Ничего «левого» в приложении нет, а называть это «обычным отображением» тоже неверно — идёт довольно много работы по проксированию. Ну и особенно это меня удивило в свете того, что я уже успешно закачивал на Google Play приложения, которые фактически только состоят из вебвью на сайт. Нюансов было два — в приложении была авторизация, и я был хозяином сайта, на который шёл вебвью. Но я это никак не указывал, и Google узнать этого не мог.
    В общем, на оба этих обвинения я ответил просьбой разобраться — сутки ответа нет, может быть ответ придёт ещё через сутки. Хотя надежды как-то мало. Так что ставим пока что приложение из APK. Если оно таки появится на Google Play, то можно будет обновиться оттуда.

    ToDo


    Если делать полноценное приятное приложение, то можно было бы добавить много всего хорошего. В том числе
    1. Стили с адаптацией к просмотру с телефона и планшета; UPD: сделано в какой-то степени;
    2. Автоматическое обновление; UPD: сделано;
    3. Корректное вырезание рекламы;
    4. Передачу торрентов торрент файлами, а не magnet ссылками;
    5. Выход из авторизованного состояния на рутрекере (да, сейчас ты там авторизуешься навсегда);
    6. Какие-то осмысленные сообщения о вероятных ошибках;
    7. Совместимость с большим количеством устройств — сейчас можно попробовать запустить на Android от 4.0 до 6 — но результат непредсказуем — надо много тестировать. У меня работает на Nexus 5 с Android 6 и на Sony Xperia Z3 с Android 5;
    8. Удобный ввод авторизации и поиска без того, чтобы тыкать на ужасные маленькие элементы веб формы;
    9. Убрать из кода некоторое количество копи-пейста;
    10. Добавить шифрование хранимой пользовательской куки уникальным для устройства ключом на случай, если данные с телефона украдут;
    11. Реализовать монетизацию приложения, свои всплывающие банеры и ссылки, которые принесли бы мне тонны золота.

    Но, к сожалению, у меня нет времени этим серьёзно заниматься — хотелось просто сделать некий работающий прототип — чтобы показать, что веб приложения в приложениях Android работают, работают хорошо и быстро. Попутно, правда, подтвердилось мнение о том, что среднее по больнице качество разработки на Android довольно сильно страдает, стандартные библиотеки не покрывают всех кейсов, и есть большое количество странных задач, которые никем толково не реализованы.
    Буду рад, если кто-то возьмёт этот код для разработки более серьёзного приложения или же зашлёт пулл реквестов — обещаю их внимательно отсматривать и применять.

    Q&A


    — Но ведь гораздо проще зайти на рутрекер через ХХХ (например, просто включив экономию трафика на телефоне или в браузере).
    — Да.

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

    — А если рутрекер заблокирует гугл за большое количество заходов с их прокси?
    — К ним и так сейчас через неё ходят, просто используя хром. Так что вряд ли. И вообще, банить всех подряд — плохая идея, так можно и чиновником стать.

    — Ваш код ужасен!
    — Да, я уже упоминал, что я не Java разработчик.

    — У меня не заработало.
    — Да, это общая проблема Android — полноценное приложение надо тестировать в 10 раз дольше, чем писать. Увы, у меня такой возможности не было. Присылайте ошибки, пулл реквесты — поправим.

    — А можно вообще так использовать Google Compression Proxy?
    — Пока непонятно — приложение забанили ещё до этого потенциального вопроса.

    — Я не доверяю вам, наверняка вы крадёте все мои пароли и скачиваете себе мои торренты.
    — Пожалуйста — соберите приложение себе из исходников.

    — А почему иконки такие страшные?
    — Посмотрите под заголовком «осталось только опубликовать» — там всё объясняется.

    — Это же раздолье для злых роботов и пауков!
    — Да нет, не обольщайтесь. С очевидностью, там тоже есть свои лимиты и проверки на роботов. Есть гораздо более простые пути для ботов.

    — Сайт криво отображается.
    — Да, местами есть проблемы. Но связанные скорее с некачественной вёрсткой.

    Привет рутрекеру


    Отдельно — несколько пожеланий для администрации рутрекера на случай, если вдруг они сюда заглянут
    хотелки
    1. Пожалуйста, подумайте о альтернативных вариантах монетизации. Всё равно большинство пользователей обходят эти жуткие гирлянды банеров адблоком.
    2. Было бы хорошо внедрить различных провайдеров авторизации — гуглового или фейсбучного, например.
    3. Обновите вёрстку и внешний вид до чего-то более красивого, удобного и желательно с мобильной версией.


    Ссылки


    UPD: пост про то, как реализовано обновление, и как вообще жить без Google Play;

    1. Для тех, кто не осилил целиком текст — ещё раз скрины: главная страница и расшаривание magnet ссылки из топика.
    2. Актуальные исходники и релизы на гитхабе;
    3. Тут можно взять меня на работу — да, я её ищу;
    4. Забавная статья о том, как использовать Google Compression Proxy+Squid. С неё я и начинал;
    5. Тут лежат исходники от compression proxy от гугла. Поскольку google code не даёт их посмотреть, можно посмотреть на моём гитхабе. Его я и разбирал;
    6. Что такое google compression proxy для пользователя и для администратора;
    7. Хороший ответ и разбор стандарта google compression proxy, правда только для HTTP траффика, не HTTPS. Есть пример реализации для firefox. Его я и переводил для статьи;
    8. Реализация прокси на Java, которая проксирует через google data compression server. Сделано для какого-то image board. Хороший код, есть что посмотреть;
    9. Единственный найденный мной вариант по проксированию HTTP трафика через HTTPS прокси при помощи библиотек apache. Его я и дорабатывал.
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 28

      +3
      Обновите вёрстку и внешний вид до чего-то более функционального и желательно с мобильной версией.

      Яндекс уже обновлял Кинопоиск, мы знаем что из этого вышло.
        0
        Рутрекер вдруг стал принадлежать Яндексу? Думаю что ваше сравнение тут не уместно.
          +3
          Еще как уместно.
          Я и не говорил что он принедлежит Яндексу.
          Я хочу сказать, что не нужно трогать то, что уже работает и пользуется популярностью.
          Я не думаю, что если Рутрекер обновит сайт, то народ еще больше восхвалит его.
          Может быть в точности да наоборот.
            +1
            Положа руку на сердце, сложно придумать что-то хуже образца из 90х годов. Хотя конечно можно, если постараться.
              +1
              По-моему у них прекрасный олдскульный дизайн, в который постепенно добавляют современные красивости.
              Не хватает лишь группировки торрентов по названию/серии/категории, как на kat.cr. Но последний тоже не идеален и к оформлению раздач у них подходят не такой скрупулезный (хоть и не совсем помойка, как TPB).
              +3
              Всегда есть альтернативный способ проверить это без потери аудитории.
              Например, last.fm прежде чем перейти на новое оформление выкатывал бету сайта и проверял реакцию публики.
              Да и голосование еще никто не отменял.
            –3
            Вышел современный сайт отлично выполняющий свою функцию, но категорично не нравящийся ретроградам, которых, к сожалению, большинство.

            А что?
              0
              А стала ли функция лучше выполняться?
                0
                Стала. Находить фильмы стало проще благодаря на порядок меньшему количеству визуального мусора.
            +1
            Вот мне интересно, все кто начинает программировать на Java через это проходят? Потому что я прям в словах "это не работает. совсем. никак." вспомнил своё единственное приложение под андроид, в котором тоже немало костылей. Вот что надо сделать и как мыслить, чтобы всё работало и получалось при разработке под андроид? Ни ужели, только опыт решает в данном случае? За что сообщество ТАК любит Java, если по всему интернету вместо элегантных решений раскиданы грязные хаки и костыли?
              +2
              Справедливости ради следует отделить java от java на Android.
              В самой джаве этих проблем нет, и те же apache библиотеки там можно использовать без угрызений совести. Проблемы возникают именно с реализацией под Android — из-за местных библиотек, и проблем совместимости, связанных с огромным зоопарком устройств. Например, проблема с webview — чисто проблема Android, java тут не при чём. Хотя вообще, если бы я упоролся и делал всё на apache Cordova, то там возможно были бы более продвинутые возможности работы с webview.

              А проблема с хаками и костылями это скорее проблема низкого уровня Android разработчиков. Для большинства это явно первый язык и приложение. Если бы люди приходили туда из каких-то крутых java проектов, то писали бы совсем по-другому.
                0
                Да, разумеется, я не про абстрактный Java в вакууме, а именно под разработку под андроид. Язык без платформы в данном случае рассматривать очень сложно.
                Ни ужели, СТОЛЬКО Android разработчиков, и все низкого уровня? Ни ужели, чтобы нормально писать под андроид, нужно сначала нормально писать (непонятно что и подо что) на Java? ИМХО сейчас этот язык имеет такое распространение только благодаря андроиду, и (так уж вышло) куча людей знакомятся с Java в Android Studio.
                По своему опыту и опыту автора этой статьи, напрашивается вывод, что похоже это не лучший вариант… Но как тогда вообще начать писать под андроид в нативной технологии с минимальными усилиями?

                P.S. К слову, мое приложение обменивалось данными с FT312D, так что ужасов WebView, я совершенно не испытывал, но все равно мне очень очень не понравилось. После Python, JS и С99, даже процесс проброса элементов интерфейса в код внушает дикий ужас и твердое осознание что как-то это СЛИШКОМ запарено чтобы быть православным подходом.
                  0
                  Неужели, чтобы нормально писать под андроид, нужно сначала нормально писать (непонятно что и подо что) на Java?

                  Нет, просто если вы пришли из мира с нормальным использованием джавы, то скорее всего качество кода будет лучше. И ещё оно будет лучше, если это не первый в жизни проект. А если первый, то качество всегда хромает — были, например, разборы приложений для хранения паролей под андроид — это вообще ужас.

                  ИМХО сейчас этот язык имеет такое распространение только благодаря андроиду, и (так уж вышло) куча людей знакомятся с Java в Android Studio.

                  Да нет, джава используется в куче различных enterprise проектов — посмотрите на hh.

                  По своему опыту и опыту автора этой статьи, напрашивается вывод, что похоже это не лучший вариант… Но как тогда вообще начать писать под андроид в нативной технологии с минимальными усилиями?

                  Тут всё зависит от того, что именно писать нужно. Есть много подходов к написанию приложений под андроид — в том числе можно писать с Apache Cordova, можно использовать C# и C++.
              +2
              «Роскомнадзор предложил штрафовать за рекламу способов обхода блокировки»
              http://politrussia.com/news/roskomnadzor-predlozhil-shtrafovat-986/

              Предлагаю информацию перенести так же на википедию. Ее точно кишка тонка заблочить будет.

                +1
                Непонятно, какую именно информацию вы предлагаете перенести на Википедию. Да и с точки зрения обхода блокировки эта статья не так ценна — как я писал, есть много более легких способов.
                0
                Да любая информация ценна будет. Я думаю было бы хорошо если бы инициативу поддержали крупные зарубежные сайты. Просто в корне у себя стали бы размещать antiblock.html со списком действий как обойти блокировку. Им на то что там роскомнадзор считает насрать, а тот весь интернет задолбается банить.

                Вообще было бы хорошим жестом — отломать им сайт и на их же сайте разместить инструкцию по тому как блокировку обходить.

                Я бы на месте Википедии и Хабра просто бы забанил все связанные с ними подсети. Уверен баттхерта бы им доставило не мало..))
                  0
                  Спасибо за приложение, отлично дополнит мой минисервер на Android. Из пожеланий:

                  1) Сделать нормальную иконку. Сейчас она выглядит… Не очень. Встречают приложения в маркете по иконке, и по моему опыту, 80% приложений с такими иконками — кривые и недостойны даже пробной установки.
                  2) убрать верхнюю панель-заголовок
                  3) внедрить стиль для рутрекера, например этот — https://userstyles.org/styles/118884/rutracker-org
                    0
                    1) Да, выглядит ужасно. Если гугл таки разбанит приложение, то иконку поменяю, иначе мало смысла. Конечно, можно сделать обновление и установку приложения и без Google play, но это тогда будет для пары-тройки энтузиастов.
                    2) А как лучше расположить кнопку для передачи magnet ссылки? По-моему, удобно, если прямо при открытии топика можно сразу передать ссылку. Я рассматривал вариант сделать кнопку плавающей на страничке — но тогда её легко не заметить.
                    3) Спасибо, посмотрю и вероятно добавлю в течении пары дней.
                      0
                      1) 4пда обеспечит достаточно широкую аудиторию, как мне кажется. Возможно и на самом рутркере разместить информацию. Хотя лучше конечно все таки добить Google Play.
                      2) Обычная плавающая стандартная иконка Material.
                        0
                        Добавлю пожелание — механизм обновления или просто уведомления о новой версии.
                          0
                          Добавил простенький механизм обновления — уведомляет о новой версии и предлагает перейти установить новую версию APK.
                        0
                        Подключил указанный стиль, всё было неплохо, но пропала панель авторизации…
                        Если будет время, можно попробовать разные CSS.
                        Подключается просто — меняем в /app/src/main/assets/rutracker.css код, и включаем обработку в коде WebViewClient:

                                if (url.getPath().equals("/custom.css")) {
                                    Log.d("WebView", "Adding custom css file...");
                        
                                    // убираем в комментарии эту строку
                                    return new WebResourceResponse("text/css", "UTF-8", null);
                                    //убираем комментарии с этого блока
                                    /*try {
                                        return new WebResourceResponse("text/css", "UTF-8", (MainContext).getAssets().open("rutracker.css"));
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }*/
                                }
                          0
                          У меня в данный момент к сожалению нет возможности проверить :( В каком смысле пропала панель, какая именно — та, что со строкой поиска?
                            0
                            Проверил на десктопе — та же фигня. Стиль рассчитан на экран с большим разрешением. У меня на ноутбуке еле влезает. А если чуть ужать страницу, то вход, регистрация, восстановление и поиск становятся неюзабельными.

                            Скажите, если увидите какой-то стиль, адаптированный под мобильные устройства.
                              0
                              Глянул, что есть — добавил неплохой. Без изысков, но убирает мусор. Работает в релизе 4.
                        • UFO just landed and posted this here
                            +1
                            Что я делаю не так?

                            Наверное запускаете Tor Browser не на Android. Речь в посте — именно про приложение для Android.
                            • UFO just landed and posted this here

                          Only users with full accounts can post comments. Log in, please.