Как стать автором
Поиск
Написать публикацию
Обновить
180.31

Android *

Пишем под самую популярную мобильную ОС

Сначала показывать
Порог рейтинга

Я проснулся, делал зарядку и размышлял о поиске работы, и вот что я осознал:

Эйчары не понимают бизнес.

Бизнес не понимает эйчаров.

Эйчары не понимают технарей.

Технари не понимают эйчаров.

Бизнес не понимает технарей.

Технари не понимают бизнес.

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

Делегирование делегированием, а эффективность эффективностью.

Еще:

Бизнес конкурирует с бизнесом.

Эйчары конкурируют с эйчарами.

Технари конкурируют с технарями.

И все конкурируют со всеми.

Как следствие - на технических собесах технари с обеих сторон стремятся доминировать друг над другом. Так как решение о наеме принимает собеседующая сторона, то она имеет преимущество над соискателем и ему приходится подстраиваться.

Как следствие, на технических собеседованиях не может быть никакой объективной оценки, идеальный кандидат здесь - не человек который решает реальные задачи, а человек который идеально подстраивается под собеседующих.

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

Выводы:

Собеседования которые проводит не "бизнес" - не помогают бизнесу найти нужных людей, а наоборот мешают ему это сделать.

Бизнес который делегирует наем рано или поздно оказывается в положении "свой среди чужих, чужой среди своих", фактически самым ценным ресурсом компании - людьми - теперь владеет не Бизнес, а Технарь и HR.

Такие дела.

Вот еще интересные мысли о наеме, с которых все началось:

Бизнес строит воронку наема, из эйчаров и технарей, в несколько этапов, и вроде все логично, происходит отсев неподходящих и выбор подходящих.

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

Понимают ли они то что происходит во всей полноте? Похоже что нет, иначе процесс был бы устроен другим образом.

А происходит следующее: соискатель приходит на собеседование, обучается на нем правильно отвечать на вопросы, если проходит то устраивается на работу, если не проходит, то идет на следующее собеседование, и так пока не устроится.

Т.е. фактически компания которая дала отказ соискателю, затратила ресурсы, обучила соискателя, и передала его другой компании. Вот что происходит на самом деле.

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

А теперь вернись к началу, вероятно теперь станет понятно откуда взялись такие тезисы :)

P.S.
Похоже всё это не является проблемой только потому, что получается микро-коммунизм в наеме. Одна компания обучает соискателей для другой, и та в свою очередь делает так же. По сути работает не система наема в компании, а побочные эффекты от нескольких систем наема разных компаний.

Откуда такие мысли:

Я уже 12 лет как в теме, и устраивался на работу сам, и искал людей на свои проекты, и собеседовал как технарь(в Android разработке) на проекты бизнеса. В общем я пощупал этого слона с разных сторон, и теперь когда я снова в активном поиске - это сложилось в объемную картину.

Теги:
+4
Комментарии14

WhatsApp сканирует сеть?

Совершенно случайно наткнулся на интересное:

У меня дома стриггерился алерт: мой домашний сервачок (он же роутер) помимо всего прочего отслеживает количество уникальных от-forward'енных $src_ip + $dst_ip + $dst_port – и алертит, когда их количество превышает некоторый порог.

И вот за последние сутки с моего телефона + телефона жены 2560 + 4082 уникальных пар $dst_ip + $dst_port (где 602x22 ниже – это соединения на 22 порт на 602 разных IP-адреса):

kate-mobile.lan (4082 IP+port pairs): 3117 TCP (1534x443, 602x22, 261x80, 237x554, 220x53, 29x23, 28x983, 21x553, 20x179, 12x1443, 9x5222, 6x5228, 4x4460, 4x21, 2x571, 2x9243, 2x240, 2x383, 2x185, 2x260, 2x299, 2x237, 2x336, 2x131, 2x512, 1x464, 1x734, 1x4416, 1x371, 1x10, 1x863, 1x895, 1x759, 1x815, 1x178, 1x830, 1x271, 1x838, 1x707, 1x629, 1x174, 1x1003, 1x894, 1x3237, 1x887, 1x962, 1x603, 1x855, 1x241, 1x494, 1x540, 1x181, 1x352, 1x454, 1x373, 1x654, 1x56, 1x646, 1x175, 1x876, 1x810, 1x556, 1x395, 1x483, 1x697, 1x212, 1x34, 1x588, 1x348, 1x605, 1x680, 1x460, 1x401, 1x224, 1x143, 1x161, 1x104, 1x655, 1x872, 1x521, 1x459, 1x911, 1x705, 1x317, 1x377, 1x807, 1x323, 1x893, 1x866, 1x142, 1x1001, 1x170, 1x920, 1x843, 1x209, 1x463, 1x156, 1x569, 1x952, 1x701, 1x184, 1x597, 1x389, 1x647, 1x8543, 1x487, 1x624, 1x537, 1x814, 1x259, 1x578, 1x26, 1x904, 1x751, 1x652, 1x795, 1x234, 1x671, 1x45, 1x4477, 1x307, 1x635, 1x651, 1x227, 1x806, 1x752, 1x203, 1x220, 1x582, 1x568, 1x153, 1x844, 1x402), 965 UDP (379x443, 278x53, 116x554, 83x123, 38x22, 22x23, 7x2002, 6x983, 4x179, 2x4123, 2x512, 2x21, 2x553, 1x363, 1x652, 1x654, 1x1003, 1x299, 1x307, 1x377, 1x680, 1x807, 1x804, 1x966, 1x685, 1x240, 1x463, 1x655, 1x806, 1x45, 1x383, 1x336, 1x153, 1x260, 1x28, 1x241, 1x603)
mobile.lan (2560 IP+port pairs): 1899 TCP (814x443, 405x22, 171x554, 168x80, 160x53, 23x983, 18x179, 18x1443, 15x23, 10x553, 9x5222, 6x21, 5x7275, 3x5228, 2x19302, 1x759, 1x37, 1x629, 1x685, 1x581, 1x582, 1x10000, 1x142, 1x250, 1x846, 1x125, 1x872, 1x657, 1x8543, 1x604, 1x90, 1x727, 1x567, 1x911, 1x739, 1x810, 1x4477, 1x866, 1x26, 1x491, 1x10, 1x156, 1x626, 1x178, 1x422, 1x977, 1x155, 1x12, 1x402, 1x683, 1x21007, 1x306, 1x595, 1x184, 1x4416, 1x472, 1x14, 1x904, 1x166, 1x165, 1x753, 1x988, 1x4434, 1x11, 1x28, 1x317, 1x622, 1x535, 1x718, 1x686, 1x637, 1x207, 1x244, 1x153, 1x7000, 1x8443, 1x966, 1x383, 1x5223, 1x985, 1x161, 1x994, 1x395, 1x898, 1x39, 1x592, 1x6447), 661 UDP (307x443, 168x53, 81x554, 36x123, 24x22, 10x23, 6x983, 6x179, 4x19302, 3x553, 3x21, 1x153, 1x685, 1x626, 1x155, 1x592, 1x19000, 1x491, 1x306, 1x472, 1x125, 1x8443, 1x28, 1x966)

Поставил себе PCAPdroid на телефон, и выяснилось, что WhatsApp (я им совсем не пользуюсь – установлен по необходимости):

  • За последний месяц съел 23 MB Wi-Fi трафика.

  • За сегодняшний день съел 92 MB Wi-Fi трафика.

  • Постоянно открывает соединения на разные IP и всякие мутные порты (ssh, ntp, ftp).

Хотелось бы верить, что это какая-то очередная защита от блокировок или вроде того, но, учитывая недавние истории про слежку за пользователями на Android, что-то не очень верится. :)

Как-то более глубоко исследовать эту ситуацию, честно говоря, нет желания (да и наверняка он подобными сканированиями занимается только изредка, чтобы не привлекать к себе лишнего внимания) – поэтому всё выше написанное исключительно JFYI, без каких-либо интересных подробностей.

P.S.: Большая просьба не воспринимать это как очередную рекламу в пользу всем известного мессенджера, который сейчас активно продвигается – все совпадения случайны.

Теги:
+9
Комментарии5

Кормак Хэйден — владелец Oasis, приложения для iPhone и смартфонов на Android, которое публикует якобы научно обоснованные рейтинги воды и фильтров, опираясь на результаты лабораторных тестов и открытые данные. Плату берут за, как утверждается, доступ к части функций, чтобы финансировать независимые (без рекламы) анализы. На сайте проекта ведётся раздел с рейтингами бутилированной воды и фильтров, поиск по водопроводной воде по городам США, а также возможность заказать домашние тест-наборы для отправки проб в лабораторию.

В личном микроблоге Хэйден опубликовал лаконичный пост. В нём он в три слова и две кавычки пожаловался, что его давно просили сделать приложение для Android, но финансовый результат Кормака разочаровал.

cormachayden_

В комментариях Хэйдену указали, что кнопка покупки на Android попросту была сломана. Кормак ответил, что локально на его машине всё работает. На самом деле ситуация ещё более смешная.

Оплата на Android в Oasis действительно сломана, это так. Однако в регионе США всё работает, указывает Хэйден. Это будет относительно легко пофиксить. Забавно именно то, что поправить уже нельзя: база данных данных Oasis крайне похожа на открытую закраудсорсенную базу данных OpenFoodFacts, а схожие же функции даёт бесплатное приложение Yuka. Кстати, Oasis по дизайну UI сильно напоминает Yuka.

Один из комментаторов даже назвал Oasis всего лишь фронтендом OpenFoodFacts. Кормак парировал, что в данных последней тяжёлых металлов и ПФАС нету и что Oasis собирает и публикует лабораторные данные, а Yuka якобы устарела, часто ошибается и не включает лабораторные измерения. Впрочем, в комментариях спросили, не заполняет ли Oasis эти значения случайными числами. Один из микроблогеров заметил, что на двух скриншотах у бренда Fiji стоит разная оценка.

На самом деле часто данные Oasis вводят в заблуждение. В комментариях к твиту нашли ошибки в выставленных предельно допустимых концентрациях: в приложении часто занижены ПДК относительно рекомендуемых властями США, и в реальности представленные количества вредных веществ представлять угрозу не могут. Зато эта дополнительная строгость к чистоте на три–четыре порядка ниже ПДК позволяет резко критиковать разные бренды за наличие в них мышьяка и тяжёлых металлов.

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

Наконец, секретом финансового успеха может быть банальный обман пользователей. Один из комментаторов указывает на тестовый период, который может запутать. Триал длится три дня, а затем начинают списывать по $4,99 в неделю. Возможно, что часть пользователей удаляет приложение и просто забывает отключить эту подписку.

Вызывает вопросы сама цена. Есть ли смысл платить по $30 ежегодной подписки за привилегию сравнивать разные бренды бутилированной воды? И вообще, заслуживает ли статуса отдельного приложения то, что может быть страницей в Интернете?

Теги:
+2
Комментарии3

Разработчик (Mobile Developer) и программист Алексей Гладков попытался независимо изучить компоненты мессенджера Max.

Теги:
0
Комментарии8

Почему разработчикам опенсорсных приложений для Android может не потребоваться подтверждать свою личность

Недавно Google анонсировала, что скоро смартфоны на базе Android будут работать только с приложениями, чьи разработчики подтвердили свою личность непосредственно Google. Но как это будут проверять? Напрашивается проверка по ключам подписи, но погодите-ка…

Если вы более-менее интересуетесь опенсорсом, наверняка вы слышали про “магазин” F-Droid. Что примечательно в нём — все приложения в его главном (единственном по умолчанию) репозитории собираются из исходников и подписываются одной сущностью — F-Droid. Эта особенность делает данный источник приложений уникальным в своём роде — в Google Play или RuStore каждый разработчик собирает и подписывает приложение сам.

Если Google не передумает и действительно введёт блокировку на “анонимных” разработчиков, вполне возможно, что F-Droid просто создаст единый аккаунт для своего ключа подписи, и продолжит спокойно предоставлять приложения даже на “сертифицированных” Android-девайсах.

Но наверняка вы скажете, что там распространяются приложения, неугодные Google, и будете правы. Однако они и так ломаются каждый месяц самой же корпорацией ввиду открытых исходников этих приложений и способов парсинга контента без официального API. Так что, думаю, обойдётся.

Что думаете?

Теги:
+7
Комментарии5

🎲 Retrofit 3.0 — что изменилось?

При поддержке блога @dolgo_polo_dev

Вышел Retrofit 3.0. А точнее в один день вышло 2 версии — Retrofit 3.0 и 2.12

Библиотека важная, поэтому попробовал разобраться, что изменилось

Самое интересное случилось в 2.12 — добавили стриминговую сериализацию из Kotlin/Java-классов в Json/Protobuf

Зачем это нужно было?

➡ чтобы большие классы не сериализовывались целиком перед отправкой запроса, а начинали это делать во время передачи данных на бэк

Это позволит чутка снизить нагрузку на процессор и оперативку, если

  • передаете объемные данные в теле запроса (1 мегабайт+)

  • где-то вызываете Retrofit.Call.enqueue() с главного потока — стриминг перенесет сериализацию с главного UI-потока в бэкграунд

Чтобы изменения заработали, нужно создавать конвертер с помощью функции withStreaming()

MoshiConverterFactory.create(moshi).withStreaming() // пример

В Retrofit 3.0 просто апнули версию OkHttp (3.14.9 -> 4.12.0). И немного поправили внутреннего кода, пару строк для совместимости с 4.12.0

Так что если обновите версию Retrofit, у вас транзитивно апнется OkHttp — будьте внимательны, берегите себя и своих тестировщиков

Из хороших новостей — Retrofit 3.0 формальный мажор, то есть бинарно совместим с предыдущими версиями (по словам разработчиков). Мажорное версию апнули для хайпа, чтобы подчеркнуть обновление OkHttp

Пруфы:

остальные посты про Android публикую в https://t.me/dolgo_polo_dev

Теги:
Рейтинг0
Комментарии0

Нужно было быстренько перехватить вызов нативной функции и посмотреть значение переменной в Android приложении. Как то давно использовал для этого замечательную утилиту Frida. Установил на планшет frida-server (root уже был) и клиент на PC, написал классический JS хук, но он не работал:

defineHandler({
  onEnter(log, args, state) {
    conslole.log('decoder_CRC_check()');
  },

  onLeave(log, retval, state) {
    const libc = Module.findBaseAddress('libc.so');
    console.log(hexdump(libc, {
      /* address: ptr('0x1000'), -- to override the base address */
      offset: 0,
      length: 64,
      header: true,
      ansi: true
    }));
  }
});

В консоли лишь получал TypeError: not a function at onEnter (D:\Distrib\Android TV\frida\hook.js:7)

Убил полдня в поисках "чего я делаю не так", при том что и официальная дока и нейронки твердят, что именно так и нужно получать базовый адрес модуля и, при необходимости, функций. Оказалось, во Frida 17 автор полностью удалил некоторые функции (а дока и нейронки еще не обновились):

  • Module.ensureInitialized()

  • Module.findBaseAddress()

  • Module.getBaseAddress()

  • Module.findExportByName()

  • Module.getExportByName()

  • Module.findSymbolByName()

  • Module.getSymbolByName()

  • Туда же статические функции Memory

И теперь надо писать цепочку вызовов:

const lib = Process.findModuleByName("libc.so");
console.log("[*] libc.so loaded at base: " + lib.base);
const funcAddr = lib.findExportByName("decoder_CRC_t_init");

Итог получился такой универсальный скрипт:

Java.perform(function () {
	const System = Java.use("java.lang.System");
    const Runtime = Java.use('java.lang.Runtime');
    const SystemLoadLibrary = System.loadLibrary.overload('java.lang.String');
    const VMStack = Java.use('dalvik.system.VMStack');
    // "ожидание"\перехват динамической загрузки нативных библиотек
    SystemLoadLibrary.implementation = function(library) {
		console.log("Loading dynamic library => " + library);
        const loaded = Runtime.getRuntime().loadLibrary0(
            VMStack.getCallingClassLoader(), library
        );
        if (library.includes("mylibname")) {
            console.log("\n[+] Hooked mylibname");
            // перехватываем только нужную нам
            hookNativeFunc();
        }
        return loaded;
    }	
});

function hookNativeFunc() {
    //тут имя полностью как называется сам файл в ресурсах
	const lib = Process.findModuleByName("libmylibname.so");
    console.log("[*] mylibname.so loaded at base: " + lib.base);
    const funcAddr = lib.findExportByName("decoder_CRC_t_init");
    if (!funcAddr) {
        console.log("[-] Function not found!");
		return;
    }
    console.log("[+] Found decoder_CRC_t_init at: " + funcAddr);
    Interceptor.attach(funcAddr, {
        onEnter: function (args) {
            var result = args[0];
            var inputPtr = args[1];
            var len = args[2].toInt32();
            console.log("\n[+] decoder_CRC_t_init called");
            console.log("    result:    " + result);
            console.log("    inputPtr:  " + inputPtr);
            console.log("    len:       " + len);
        },
        onLeave: function (retval) {
            //нужный адрес массива, например из IDA PRO
            const wordArrayOffset = 0x5B2C04;
            const wordArray = lib.base.add(wordArrayOffset);
			var ptr = new NativePointer(wordArray); // современный вариант чтения
            console.log("[*] 5B2C04 contents:");
            try {
                console.log(hexdump(ptr, {
				  offset: 0,
				  length: 512,
				  header: true,
				  ansi: true
				}));
            } catch (e) {
                console.log("[!] Error reading 5B2C04:", e);
            }
            console.log("Return value:", retval);
        }
    });
}

Запускается так frida -U -f com.android.app -l hook.js

Теги:
Всего голосов 5: ↑5 и ↓0+6
Комментарии5

Как ускорить Android-разработку и избавиться от мучительно долгих запусков эмуляторов ради простого теста? 

Ответ — Robolectric — мощный инструмент для UI‑тестирования Android‑кода без эмулятора. 

Позволяет запускать юнит-тесты Android-приложений прямо в JVM, без эмуляторов и физических устройств. Экономия на каждом тестовом прогоне, обратная связь почти мгновенная.

В Android‑комьюнити у Robolectric неоднозначная репутация из‑за трудностей совместимости с другими библиотеками. Но…его почти бесценные возможности пробудили любопытство и желание копнуть глубже и осмыслить этот инструмент. 

Так и родилась статья «Мечтают ли андроиды о Robolectric? Разбираем фреймворк по косточкам» от Павла Нестеренко, нашего Android-разработчика.

Если вы устали ждать, пока эмулятор запустится, и хотите гонять юнит-тесты за секунды прямо в JVM, то рекомендуем статью к прочтению!

Теги:
Рейтинг0
Комментарии0

Save the date: 4 июля встречаемся на Android Meetup!

В программе доклады от спикеров Wildberries & Russ и Альфа-Банка, Q&A-сессия с розыгрышем мерча, нетворкинг и фуршет для классного завершения вечера.

Поговорим о том, как оживить виджеты, подружить Compose с Koin и навигацией, а заодно встроить одно Android-приложение в другое без боли...или с болью:

«Виджеты на Android: это просто?»
Александр Гирев, Android Team Lead продуктовой команды WB Partners

«Compose+Koin+JetpackNavigation: что мы поняли за 2 года»
Арсений Шпилевой, Android-разработчик кор-команды WB Partners

«Интеграция Android-приложений: подходы и лучшие практики»
Абакар Магомедов, главный техлид разработки в Альфа-Банке

Когда: 4 июля 18:00 (сбор гостей с 17:00)
Где: Москва, пространство Весна + онлайн-трансляция

Регистрация уже открыта — присоединяйтесь онлайн или офлайн!

Теги:
Рейтинг0
Комментарии0

Telegram запустил конкурс для разработчиков под Android. Призовой фонд: $50 000. Срок сдачи работ: 11 июля, 23:59 по дубайскому времени (UTC+4). Объявление итогов: июль 2025.

В дополнение к призовым, победитель конкурса сможет присоединиться к команде Telegram в Дубае и зарабатывать 1 миллион долларов в год после вычета налогов.

Задача: Внедрить обновлённый интерфейс профилей в приложение Telegram для Android в строгом соответствии с предоставленным дизайном.

Полные условия конкурсного задания, технические подробности и макеты представлены в отдельном канале платформы.

Теги:
Всего голосов 1: ↑1 и ↓0+1
Комментарии0

Вы - начинающий разработчик под Андроид или просто пишете "для себя" и решили отображать динамическую анимацию через SurfaceView. Например, взяв за основу вот этот код или похожий. Вы разместили SurfaceView или его наследника (у меня MySurfaceView) в activity layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activityMain"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <agalilov.doppler.MySurfaceView
        android:id="@+id/dopplerView"
        android:background="#040947"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginBottom="15dp"
        app:layout_constraintBottom_toTopOf="@+id/btnStartStop"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btnStartStop"
        android:layout_width="118dp"
        android:layout_height="56dp"
        android:layout_marginStart="16dp"
        android:layout_marginBottom="16dp"
        android:text="@string/start"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/dopplerView" />

</androidx.constraintlayout.widget.ConstraintLayout>

Запускаете приложение и... ничего не работает: SurfaceView не меняется, картинки нет! Ошибок тоже нет, код рисования выполняется впустую.

Я провёл почти всю ночь, разбираясь в причине. Оказалось, для SurfaceView, который размещён внутри другого View, по-умолчанию используется z-order "позади" родительского View. Это поведение, документированное в разных источниках, оказалось для меня неожиданным.

Лечится просто: при инициализации (в конструкторе класса-наследника) SurfaceView устанавливаем setZOrderOnTop(true):

public MySurfaceView(Context context, AttributeSet attributeSet) {
    super(context, attributeSet);
    setZOrderOnTop(true);
    . . .
}

Вот такая история :)

Теги:
Всего голосов 5: ↑5 и ↓0+7
Комментарии0

URLCheck: Полезная утилита для инспекции URL на Android

Хочу поделиться находкой, которая многим здесь придется по душе. Каждый из нас хоть раз с недоверием кликал по сокращенной или странной ссылке, присланной в мессенджере или почте. Сколько раз мы неосознанно переходили по ссылкам с кучей UTM-меток и прочего трекающего мусора?

Недавно я наткнулся на утилиту для Android, которая решает эту проблему - URLCheck.

Это не браузер, а приложение-посредник. Вы назначаете его для открытия ссылок по умолчанию, и когда вы кликаете на любую ссылку, вместо того чтобы сразу открыть его в браузере, URLCheck перехватывает его и показывает вам вот такое окно:

Вот несколько любопытных ключевых фич:

  • Очистка от трекеров: Автоматически вырезает из линка весь мусор вроде UTM-меток и параметров отслеживания, используя правила проекта ClearURLs.

  • Сканер VirusTotal: Позволяет в один клик отправить ссылку на проверку в VirusTotal и посмотреть отчет. (Нужен свой бесплатный API-ключ).

  • Раскрытие коротких ссылок: Показывает, куда на самом деле ведет укороченный линк типа bit.ly - зачастую фишинговые ссылки скрываются за укороченными линками, чтобы усложнить блокировки.

  • Проверка по хост-листам: Интегрируется со списками StevenBlack (adware, malware, fakenews и т.д.) и предупреждает, если домен находится в одном из них.

  • Pattern-checker: Для продвинутых - можно настроить свои правила на основе регулярных выражений. Например, автоматически заменять http на https или twitter.com на nitter.net.

  • Полный контроль над линком: Вы можете вручную отредактировать URL, посмотреть историю изменений или просто скопировать/поделиться ей.

И самое главное — приложение с открытым исходным кодом! Настоящий швейцарский нож для тех, кто заботится о своей безопасности и приватности в сети.

Где скачать:

В общем, рекомендую попробовать. Для меня это стало одним из приложений категории "must-have".

Теги:
Всего голосов 3: ↑3 и ↓0+4
Комментарии0

Google опубликовала ролик в рамках своей юмористической рекламной кампании Best Phones Forever с «диалогом» между персонифицированными смартфонами Pixel и iPhone. Повествование разворачивается вокруг анонсированных Apple «прорывных» функций iOS 26, которые, по задумке Google, на самом деле уже давно доступны пользователям Pixel.

В видео iPhone перечисляет «новые» возможности операционной системы Apple: перевод сообщений и звонков в режиме реального времени, интеллектуальный отбор вызовов и умное удержание. Выясняется, что аналогичный функционал появился на устройствах Pixel еще пять лет назад, что ставит под сомнение новизну представленных Apple решений.

Теги:
Рейтинг0
Комментарии1

Ближайшие события

📜 M-V-подставь_свое

Model-View-*** - это шаблоны проектирования
Важное уточнение: это шаблоны проектирования только для presentation слоя, а не для целого приложения

💃 Model
- это как раз та часть приложения о которой мы ближайшее время говорить не будем
Чаще всего ее называют бизнес логикой, но это не совсем верно
Пока, лучше всего воспринимать ее как модель данных которую наше приложение хочет передать пользователю
Причем не важно будет это Ui или API, или что-то другое
MV шаблоны не про frontend, а про то как передать данные клиенту, кем бы он ни был

🖼 View
- это само представление данных пользователю. То, что он по итогу получит
В мире андройд это обычно Activity, Fragment, View или Compose

🪝***
- это какая-то прослойка между моделью данных и их представлением пользователю

Для чего все эти шаблоны вообще придумали?

Дело в том, что View это какой-то вариант отображения данных клиенту 🏐
И часто возникает ситуация, что нужно создать другой вариант отображения ⚽️
Это может быть как бизнес потребность в перекраске кнопок и проведении при этом ab-тестов, 🏀
или желании разработчиков заменить технологию отображения 🏈

Например, у вас было консольное приложение, а вы вдруг захотели сделать для него UI (GitBash|GitUi здравствуйте),
ну или решили заменить Android.View на Compose

Во всех этих случаях нам хочется чем-то разделить саму View и работу с Model, чтобы иметь возможность заменить только View, не трогая ничего другого

В Android, к этому еще добавляется проблема пересоздания View при изменении конфигурации. Когда вы переворачиваете экран (и не только), весь ваш UI просто уничтожается и создается полностью заново. Хотя с точки зрения пользователя это все тот же экран с теми же данными 🫠

Это создает дополнительную потребность отвязать View от остального приложения, чтобы можно было ее подменять прямо в рантайме

Основные шаблоны это MVC, MVP, MVVM и MVI
О них мы и поговорим в следующих постах...

ПС. Посты с большим опережением есть в тг канале из описания профиля

Теги:
Всего голосов 3: ↑2 и ↓1+1
Комментарии1

Магазину приложений RuStore исполнилось три года. Количество установок этого приложения на устройствах пользователей превысило 100 млн.

25 мая 2022 года VK при поддержке Минцифры запустила открытое бета‑тестирование отечественного магазина мобильных приложений для Android под названием RuStore.

В начале февраля 2023 года RuStore объявил о завершении этапа бета‑тестирования магазина приложений. Также создатели платформы перевели интерфейс консоли разработчика на английский язык для удобства иностранных издателей и партнёров.

В декабре 2024 года месячная аудитория магазина приложений RuStore составила 50 млн пользователей старше 12 лет по всей России, согласно исследованию Mediascope. Аудитория Xiaomi Mi Store составила 19 млн, Samsung Galaxy Store — 14 млн, HUAWEI AppGallery — 10 млн, рассказали Хабру в пресс‑службе RuStore. А в Минцифры заявили, что RuStore от VK обошёл по числу пользователей в России App Store от Apple.

В VK добавили, что в каталоге RuStore уже более 50 тысяч приложений, доступных на ОС Android, Harmony OS и «Аврора», от разработчиков из 40 стран мира. Также вышли версии RuStore для электронных книг и умных телевизоров, для проекторов, Hi‑Fi‑аудиоплееров, игровых консолей, кассовых терминалов, умных часов.

Теги:
Всего голосов 6: ↑2 и ↓40
Комментарии9

Google I/O 2025: два вечера главных анонсов вместе с Surf

20 и 21 мая — подключайся к нашим стримам по Google I/O. Будем вместе следить за анонсами новинок, делиться первыми впечатлениями и обсуждать всё самое интересное из мира технологий и разработки в прямом эфире.

Смотрим и комментируем:

  • 20 мая (вторник)
    → 20:00 — Google Keynote: все главные анонсы и будущее технологий от Google.

  • 21 мая (среда)
    → 20:00 — What’s new in Android development tools: новинки для Android-разработчиков.
    → 21:00 — What’s new in Flutter: свежие обновления для Flutter-сообщества.

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

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

Теги:
Рейтинг0
Комментарии0

Android-приложение «Контакты»: работает — не трогай

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

Чтобы заменить стандартные типы полей, нужно добавить новую базу данных с доступными типами полей, а также реализовать отображение и возможность выбора поля. Для этого пришлось во многом переписать код редактирования полей контакта, где и без этого логика была непростой. Теперь стало совсем сложно: при добавлении или обновлении поля в contentProvider нужно указывать тип поля, так что мы начали указывать «custom».

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

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

Создание схемы БД и инициализация стандартными значениями происходила в отдельном потоке, так что у нас получилась небольшая гонка потоков. UI готов отобразить экран и идет в БД за данными, но БД не успевает инициализироваться, так что запрос приводил к критической ошибке. Баг воспроизводился при попытке обратиться к БД только при первом холодном запуске на устройстве или после очистки данных, так как здесь приложению приходится заново создавать схему базы данных.

Пришлось опять добавлять костыль: в отдельной корутине ожидать инициализации БД и только потом начинать рисовать экран...

Дмитрий Бражник, старший инженер-программист в департаменте разработки мобильных приложений YADRO, рассказал в статье, как его команда пыталась допилить стандартное AOSP-приложение «Контакты» и к чему они в итоге пришли.

Теги:
Всего голосов 3: ↑2 и ↓1+2
Комментарии0

Хардкодить допоздна? А может, лучше нет, ворк?

>> Регистрация и программа <<

23 апреля в 20:00 приглашаем воронежских разработчиков на неформальный митап. Для тех, кто не сможет прийти офлайн, будет трансляция.

Никаких скриншотов кода на слайдах. Никакого душного обсуждения документации. Поговорим о том, что окружает нас вне работы. Прокачаем софт-скиллы и нетворкинг.

В программе митапа три доклада:

  • Лёша, Android-разработчик Surf — «Дедлайн "вчера": как работать с приоритетами».

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

  • Дима, Flutter-разработчик Surf — «Тимлид — друг или враг? Или так»?

    Расскажу о роли тимлида, но со стороны нижестоящего сотрудника. Что мне нравится/что не нравится в лиде, что для меня кажется полезным, а смысл чего я не понимаю.

  • Кирилл, iOS-разработчик, наш друг и гость из Una Financial — «Work-life health для IT-шника среднего возраста».

    Поделюсь жизненными проблемами разработчиков и способами их решения. Внимательный слушатель вообще сможет их избежать! Обсудим, как сделать жизнь лучше, повысить её качество. Максимально продлим трудоспособный возраст.

Митап пройдет 23 апреля, в 20:00, в воронежском пространстве «Eventuki»: ул. Фридриха Энгельса, 52.

Участие в митапе бесплатное, чтобы прийти или получить ссылку на трансляцию, нужно зарегистрироваться 👈

Запись трансляции обязательно сохраним, но если вы из Воронежа, мы очень ждём понетворкать вживую. До встречи 😉

Теги:
Рейтинг0
Комментарии0

Вышло видеоруководство по переводу смартфонов Pixel на GrapheneOS с упором на конфиденциальность, включая настройку ключевых параметров и установку приложений, а также способы работать с сервисами Google Play с отключением трекеров.

Теги:
Всего голосов 3: ↑1 и ↓2+1
Комментарии1

Добавлен Room! :)
Ранее я уже делился статьей про Delight SQL Viewer — библиотеку, позволяющую отлаживать SQLDelight-базу данных напрямую внутри вашего Kotlin Multiplatform-приложения. Однако в одном из наших внутренних проектов используется Room Multiplatform и хотелось иметь возможность отладки БД и в нем. Так и появилась вторая версия библиотеки, которая теперь поддерживает и Room, и SQLDelight.

Что делает библиотека?

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

  • Автоматически добавляет иконку-ярлык для быстрого запуска (Android и iOS).

  • На Desktop ярлыки не поддерживаются. Для запуска интерфейса используйте обычную кнопку или меню в вашем UI.

  • Легко отключается в продакшен-сборках — можно либо не вызывать init, либо подключать stub-модуль вместо основной библиотеки.

Как использовать?

Зависимости (shared/build.gradle.kts)

val isRelease = /* Ваша логика определения релизной сборки */

dependencies {
    if (isRelease) {
        // В релизе – stub, чтобы не вшивать весь отладочный UI.
        api("ru.bartwell.delightsqlviewer:stub:2.0.0")
    } else {
        // В debug – полная функциональность.
        api("ru.bartwell.delightsqlviewer:runtime:2.0.0")
        api("ru.bartwell.delightsqlviewer:core:2.0.0")
        // Выберите, что используете:
        api("ru.bartwell.delightsqlviewer:sqldelight-adapter:2.0.0")
        // или
        // api("ru.bartwell.delightsqlviewer:room-adapter:2.0.0")
    }
}

Инициализация

  • SQLDelight (Android):

    DelightSqlViewer.init(
        object : SqlDelightEnvironmentProvider() {
            override fun getDriver() = sqlDelightDriver
            override fun getContext() = context
        }
    )
  • Room (Android):

    DelightSqlViewer.init(
        object : RoomEnvironmentProvider() {
            override fun getDriver() = roomDatabase
            override fun getContext() = context
        }
    )
  • iOS (пример для SQLDelight):

    let provider = SqlDelightEnvironmentProvider(driver: sqlDriver)
    DelightSqlViewer.shared.doInit(provider: provider, isShortcutEnabled: true)

    Аналогично и для RoomEnvironmentProvider.

    Также, чтобы ярлык корректно работал на iOS, в вашем AppDelegate нужно переопределить методы обработки ярлыков, например:

    class AppDelegate: NSObject, UIApplicationDelegate {
        func application(
            _ application: UIApplication,
            configurationForConnecting connectingSceneSession: UISceneSession,
            options: UIScene.ConnectionOptions
        ) -> UISceneConfiguration {
            return ShortcutActionHandler.shared.getConfiguration(session: connectingSceneSession)
        }
    }

    Или вызовите DelightSqlViewer.shared.launch() в обработчике вашего Shortcut.

  • Desktop:

    DelightSqlViewer.init(
        object : SqlDelightEnvironmentProvider() {
            override fun getDriver() = sqlDelightDriver
        }
    )

Аналогично и для RoomEnvironmentProvider.

Запуск

После инициализации вызов DelightSqlViewer.launch() откроет интерфейс просмотра и редактирования (на Android/iOS можно также запустить через ярлык при долгом тапе на иконку приложения).

Button(onClick = { DelightSqlViewer.launch() }) {
    Text("Open DB Viewer")
}

Итог

Теперь Delight SQL Viewer покрывает оба основных способа хранения данных в мультиплатформенных проектах — SQLDelight и Room Multiplatform. Если нужно быстро проверить содержимое вашей БД или вручную поправить что-то прямо во время тестирования, эта библиотека может сэкономить кучу времени. Ну и, конечно, легко «прячется» в релизе, чтобы никакого отладочного UI не оставалось.

Ссылка на репозиторий: https://github.com/bartwell/delight-sql-viewer

Буду рад фидбэку и вопросам!

Теги:
Всего голосов 1: ↑1 и ↓0+3
Комментарии0

Вклад авторов