Невозможно отучить людей изучать самые ненужные предметы.
Введение в CSS
Преимущества стилей
Добавления стилей
Типы носителей
Базовый синтаксис
Значения стилевых свойств
Селекторы тегов
Классы
CSS3
Надо знать обо всем понемножку, но все о немногом.
Идентификаторы
Контекстные селекторы
Соседние селекторы
Дочерние селекторы
Селекторы атрибутов
Универсальный селектор
Псевдоклассы
Псевдоэлементы
Кто умеет, тот делает. Кто не умеет, тот учит. Кто не умеет учить - становится деканом. (Т. Мартин)
Группирование
Наследование
Каскадирование
Валидация
Идентификаторы и классы
Написание эффективного кода
Вёрстка
Изображения
Текст
Цвет
Линии и рамки
Углы
Списки
Ссылки
Дизайны сайтов
Формы
Таблицы
CSS3
HTML5
Блог для вебмастеров
Новости мира Интернет
Сайтостроение
Ремонт и советы
Все новости
Справочник от А до Я
HTML, CSS, JavaScript
Афоризмы о учёбе
Статьи об афоризмах
Все Афоризмы
Помогли мы вам |
Yet Another Tamper Detection in Android — статья о том, как защитить приложение с помощью проверки цифровой подписи в нативной библиотеке.
Любое приложение для Android имеет цифровую подпись, с помощью которой можно подтвердить его авторство. Проблема лишь в том, что цифровая подпись сверяется только во время обновления приложения (подписи не совпадают — обновить нельзя), но не его первой установки. Это значит, что взломщик может разобрать любое приложение, взломать его или внедрить новую функциональность, а затем собрать с использованием своего ключа. А пользователь спокойно его установит, при необходимости удалив оригинальную версию приложения.
Бороться с пиратством можно, внедрив код проверки цифровой подписи прямо в само приложение. При старте приложение получает свою собственную цифровую подпись, сравнивает ее с сохраненным образцом и, если они не совпадают, завершает само себя, показав сообщение о пиратстве.
Недостаток этого подхода в том, что для сверки контрольной суммы используются стандартные API Android (packageManager.getPackageInfo()
), ориентируясь по которым взломщик может найти код сверки контрольной суммы и просто вырежет его из приложения.
Автор статьи предлагает разместить данный код в написанной на языке С библиотеке. Вместо API Android эта библиотека использует собственные средства сверки цифровой подписки (в частности, код из библиотек libzip и mbed TLS). Также в библиотеке применен ряд средств защиты от реверса, таких как собственные реализации функций libc и позаимствованный из OpenSSL способ определить, что код библиотеки изменен.
Последний работает так: при сборке в секции text (содержит код) и rodata (содержит константы, включая хеш сертификата) вставляются специальные маркеры, которые помечают начало и конец секции. Далее вычисляется HMAC для данных между этими маркерами и записывается в секцию данных. Во время вызова функции сверки цифровых подписей библиотека проверяет собственную целостность с помощью HMAC.
Код проекта опубликован на GitHub.
JaDX decompile of com.askgps.personaltrackercore — декомпилированные исходники приложения «Социальный мониторинг», созданного по заказу мэрии Москвы за 180 миллионов рублей. Приложение получило в среднем одну звезду и было удалено из Google Play меньше чем через сутки после публикации.
Р?зучая РёСЃС…РѕРґРЅРёРєРё, РјРѕР¶РЅРѕ заметить, что приложение РЅРµ применяет никакой, даже самой простой обфускации Рё передает данные РЅР° сервер РјСЌСЂРёРё РњРѕСЃРєРІС‹ РІ открытом РІРёРґРµ (голый HTTP, без шифрования), Р° РІ качестве метода аутентификации использует IMEI (зная IMEI смартфона жертвы, злоумышленник может «отправить» его РЅР° РґСЂСѓРіРѕР№ край страны, сменить фотку Рё РґСЂСѓРіРёРµ сведения).
Для распознавания лиц приложение использует эстонский сервис identix.one, РЅР° который, СЃСѓРґСЏ РїРѕ всему, разработчики залили фотографии всех жителей Р Р¤. Рто значит, что, имея РЅР° руках токен сервиса, выдранный РёР· приложения, злоумышленник РјРѕРі Р±С‹ использовать сервис для идентификации людей РїРѕ фотографии. Рљ счастью, РІСЃРµ API СѓР¶Рµ закрыты.
Примерно через неделю свой аналог «Социального мониторинга» выпустило уже Минкомсвязи. Госуслуги СТОП коронавирус (исходники) оказалось более качественным и таких зияющих дыр уже не содержало. Что, впрочем, не помешало ему получить среднюю оценку в 1,6 звезды.
App Standby Buckets In Android — небольшая заметка о функции App Standby Buckets, появившейся в Android 9.
App Standby Buckets — новая энергосберегающая функция, расширяющая Рё дополняющая механизм Doze, работающий СЃ Android 6. Р?дея РЅР° этот раз состоит РІ том, чтобы разделить РІСЃРµ установленные РЅР° смартфоне приложения РЅР° категории РІ зависимости РѕС‚ того, насколько часто РѕРЅРё используются.
Основных категорий пять:
В простейшем случае Android группирует приложения по категориям, основываясь на времени последнего запуска, но производитель смартфона может использовать другие способы группировки. Например, в смартфонах Google Pixel для этих целей приспособлена нейронная сеть.
В зависимости от группы система применяет к приложениям различные ограничения, включая ограничения на запуск фоновых задач (Jobs), срабатывание таймеров (Alarm), доступность сетевых функций и push-уведомлений (Firebase Cloud Messaging — FCM):
Группа | Jobs | Alarms | Сеть | FCM |
---|---|---|---|---|
Active | Без ограничений | Без ограничений | Без ограничений | Без ограничений |
Working set | Задержка до 2 часов | Задержка до 6 минут | Без ограничений | Без ограничений |
Frequent | Задержка до 8 часов | Задержка до 30 минут | Без ограничений | 10 в день |
Rare | Задержка до 24 часов | Задержка до 2 часов | Задержка до 24 часов | 5 в день |
Р?нтересный побочный эффект этой системы РІ том, что если РІСЃРµ взаимодействие пользователя СЃ приложением будет сводиться только Рє прочтению Рё смахиванию уведомлений, то через несколько дней приложение перейдет РІ РіСЂСѓРїРїСѓ Rare Рё будет серьезно урезано РІ возможностях.
Также следует иметь в виду, что приложение не будет урезано в правах, если находится в списке исключений системы энергосбережения или если телефон на зарядке.
A cautionary tale on Android: do not call System.exit() — небольшая статья о том, почему не стоит использовать System.exit()
в своем приложении.
Документация Android говорит, что метод System.exit()
(и его эквивалент в Kotlin: exitProcess()
) делает следующее: завершает текущую виртуальную машину и сообщает системе, корректным ли было завершение (0 — все нормально, больше нуля — произошло что-то плохое).
Так как в Android каждое приложение исполняется в собственной виртуальной машине, можно предположить, что System.exit()
, РїРѕ сути, РїСЂРёРІРѕРґРёС‚ Рє полному уничтожению приложения. Рто действительно так, РЅРѕ есть РѕРґРёРЅ нюанс: если РІ момент вызова Сѓ приложения были РґСЂСѓРіРёРµ активности РІ состоянии paused, то РѕРЅРё останутся РІ стеке активностей. Рто, РІ СЃРІРѕСЋ очередь, приведет Рє тому, что после вызова System.exit()
будет уничтожена текущая активность и само приложение, а затем система вернет управление предыдущей активности приложения. Но так как приложение уже мертво, система перезапустит его, чтобы показать активность.
Решить эту проблему в большинстве случаев можно, используя метод finishAffinity()
, который приводит к корректному завершению текущей активности приложения, а также всех активностей с тем же значением affinity. Так как по умолчанию Android назначает всем активностям приложения одинаковый affinity, равный имени пакета приложения, это приведет к закрытию всех активностей.
App size reduction at Microsoft SwiftKey — сборник заметок разработчиков клавиатуры SwiftKey (Microsoft) о том, как сократить размер скачиваемого и установленного приложения.
1. Установленное приложение весит намного больше скачиваемого потому, что во время установки Android сохраняет в памяти устройства не только сам APK-файл, но и некоторые извлеченные из него компоненты: верифицированный файл DEX (VDEX — Verified DEX) и нативные библиотеки. Также через некоторое время виртуальная машина создает файл ODEX — оптимизированную версию файла DEX, пропущенную через AOT-компилятор (некоторые части байт-кода заменяются на машинные инструкции). Причем начиная с Android 9 этот файл может быть получен сразу из Google Play.
В целях тестирования файл ODEX можно создать принудительно:
adb shell cmd package compile -m speed-profile -f имя.пакета
2. В случае со SwiftKey помогли следующие флаги ProGuard: repackageclasses, renamesourcefileattribute и allowaccessmodification. Но появился побочный эффект: еще большее запутывание стек-трейсов в системе анализа сбоев.
3. Компилятор R8 (в новых версиях Android Studio включен по умолчанию) сократил размер установленного приложения на 1,3 Мбайт, но замедлил время его старта.
4. По умолчанию при сборке приложения среда разработки сжимает нативные библиотеки. При установке приложения на устройство Android распаковывает библиотеки в специальный каталог с данными приложения. Это приводит к дополнительному расходу пространства устройства. Чтобы поменять такое поведение и заставить Android использовать библиотеки прямо из пакета, следует внести два изменения в проект.
В файл build.gradle
добавить такие строки:
android {
aaptOptions {
noCompress 'so'
...
}
...
}
В AndroidManifest.xml
— такие:
<application android:extractNativeLibs="false" ...>
Имей в виду, что некоторые библиотеки, например SoLoader, будут распаковывать библиотеки принудительно, несмотря на используемые опции.
5. По умолчанию при обфускации/минимизации приложения среда разработки удалит все неиспользуемые ресурсы. Также ты можешь удалить их с помощью опции Android Studio: Refactor -> Remove Unused Resources.
6. Используемое приложением место можно сократить, преобразовав изображения в формат WebP (клик правой клавишей на папке drawable, затем пункт Convert to WebP). Экономия составит примерно 25%. Еще большего выигрыша можно достигнуть, заменив растровые изображения на векторные. Однако в этом случае автоматически преобразовать их не получится.
7. При сборке среда разработки помещает все используемые приложением строки в файл resources.arsc
. РўСѓРґР° попадают строки РЅР° всех языках, включая строки РёР· используемых РІ проекте библиотек. Проблема здесь РІ том, что, если библиотека переведена РЅР° большее количество языков, чем само приложение, строки РЅР° этих языках РІСЃРµ равно попадут РІ пакет. Р?збавиться РѕС‚ РЅРёС… РјРѕР¶РЅРѕ, перечислив используемые приложением языки РІ конфиге Gradle:
android {
defaultConfig {
resConfigs "en", "es"
}
}
Теперь в приложение попадут строки только на английском и испанском.
8. Хороший выигрыш в размере загружаемого приложения даст использование App Bundle. Новые версии Android Studio по умолчанию предлагают собирать приложение в App Bundle вместо классического APK. Bundle затем можно залить в Google Play, и он автоматически будет разбит на несколько APK для разных платформ, включая отдельные дополнительные APK для разных языков и регионов. В этом случае итоговый размер пакета, который загружает на смартфон пользователь, обычно становится намного меньше.
Все эти техники позволили сократить размер пакета SwiftKey на 50% (с 27,6 до 14,3 Мбайт), а занимаемое место после установки — на 40% (с 81,5 до 48 Мбайт).
Android Battery Testing at Microsoft YourPhone — еще один материал разработчиков из Microsoft. На этот раз авторство принадлежит команде приложения YourPhone (того, что позволяет управлять телефоном из Windows), а статья посвящена измерению потребления батареи.
Большая часть статьи — вода, но в конце есть мякотка — скрипт для запуска тестирования батареи и часть кода для парсинга результатов работы скрипта. Код скрипта:
## Рмулируем отключение смартфона РѕС‚ источника питания
adb shell dumpsys unplug
## Сбрасываем статистику использования батареи
adb shell dumpsys batterystats --reset
## Запускаем тесты
...
## Останавливаем тесты
## Получаем статистику работы батареи (вывод этой команды надо сохранить)
adb shell dumpsys batterystats
## Отключаем эмуляцию отключения от источника питания
adb shell dumpsys batterystats reset
Далее результат работы команды dumpsys batterystats reset
можно пропарсить, чтобы получить сводные данные об использовании батареи. В статье приведен фрагмент приложения на C#, которое выводит такой результат:
Total Usage: 62.1mAh
Cpu Usage: 1.21mAh
Wifi Usage: 60.9mAh
Wakelock Usage: 0mAh
Bluetooth Usage: 0mAh
Разумеется, его можно переписать на любом другом языке.
Showing the Android Keyboard Reliably — статья разработчиков Square о том, как показать клавиатуру и не получить проблем.
Суть проблемы: в Android есть способ форсировать показ клавиатуры без необходимости дожидаться, пока пользователь кликнет на поле ввода:
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT)
Он работает, но только в том случае, если поле ввода (в данном случае — editText
) будет иметь фокус в момент вызова метода showSoftInput()
. Это ограничение можно обойти, передав методу showSoftInput()
флаг InputMethodManager.SHOW_FORCED
. Но тогда клавиатура не будет спрятана автоматически и останется на экране, например, если пользователь свернет приложение.
Статья описывает способ обхода этих проблем. Тебе необходимо повесить на поле ввода листенер, который сработает, когда поле ввода получит фокус, и в этот момент покажет клавиатуру.
Код функции-расширения, которая корректно показывает клавиатуру во всех случаях:
fun View.focusAndShowKeyboard() {
fun View.showTheKeyboardNow() {
if (isFocused) {
post {
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
}
}
}
requestFocus()
if (hasWindowFocus()) {
showTheKeyboardNow()
} else {
viewTreeObserver.addOnWindowFocusChangeListener(
object : ViewTreeObserver.OnWindowFocusChangeListener {
override fun onWindowFocusChanged(hasFocus: Boolean) {
if (hasFocus) {
this@focusAndShowKeyboard.showTheKeyboardNow()
viewTreeObserver.removeOnWindowFocusChangeListener(this)
}
}
})
}
}
In-App Updates: Getting Started — большой туториал по реализации In-App Updates — функции, с помощью которой приложение может принудительно обновить себя или вывести уведомление об обновлении.
Функция реализована в библиотеке Google Play Core и предлагает два способа обновления приложения: immediate и flexible. Первый принудительный: приложение автоматически запускает обновление, а пользователю остается только наблюдать. Второй позволяет проверить наличие обновления и вывести сообщение/уведомление/кнопку, нажав на которое пользователь может самостоятельно запустить процесс обновления.
И в том и в другом случае проверить, есть ли новая версия, и запустить обновление очень просто. Например, принудительно обновить можно всего в несколько строчек:
private const val REQUEST_UPDATE = 100
fun checkForUpdate(activity: Activity) {
val appUpdateManager = AppUpdateManagerFactory.create(getAppContext())
val appUpdateInfo = appUpdateManager.appUpdateInfo
appUpdateInfo.addOnSuccessListener {
handleImmediateUpdate(activity, appUpdateManager, appUpdateInfo)
}
}
private fun handleImmediateUpdate(activity: Activity, manager: AppUpdateManager, info: Task<AppUpdateInfo>) {
if ((info.result.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE ||
info.result.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) &&
info.result.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
manager.startUpdateFlowForResult(info.result, AppUpdateType.IMMEDIATE, activity, REQUEST_UPDATE)
}
}
Все, что делает этот код, — проверяет, есть ли обновление (UpdateAvailability.UPDATE_AVAILABLE
), подходит ли оно для принудительной установки (AppUpdateType.IMMEDIATE
), и, если да, устанавливает его.
Flexible-обновления работают примерно так же с тем исключением, что обновление можно запустить в фоне, а затем попросить пользователя перезапустить приложение.
The Top 20 Android Studio Plugins — обзор двадцати плагинов Android Studio на все случаи жизни. Наиболее интересные экземпляры:
|
|