company_banner

Патчим AndroidX


    На Google I/O 2018 была представлена замена существующим support-библиотекам — AndroidX


    Изначально, support-библиотеки разрабатывались для обратной совместимости новых API-интерфейсов и были тесно связаны с операционной системой. Разработка support-библиотек велась во внутренних ветках, которые периодически вливались в Android Open Source Project (AOSP). Такой подход ограничивал мерж пулл-реквестов от сообщества небольшими отрезками времени когда код AOSP и внутренний код гугла были синхронизированы. Кроме того, для работы с support библиотеками необходимо было выкачивать весь код платформы, а это более 40ГБ исходного кода. Для моего диска объемом 250 ГБ это достаточно много.


    Текущий функционал support-библиотек гораздо шире изначальной задумки. Например, там реализован компонент для упрощения разработки пользовательского интерфейса AppCompat, компонент для работы с базами данных Room, компонент для фоновых задач WorkManager. Многие из этих библиотек изначально имеют обратную совместимость и слабо привязаны к Android API. Цифра в номере support-библиотеки означает минимальный уровень API, который она поддерживает. Например, support-v7 поддерживает Android API версии 7 и выше. Однако, начиная с версии 26.0.0 support-библиотеки поддерживают Android API 14 и выше. Отдельную боль доставляет необходимость одновременного обновления всех support-библиотек. Все это указывает на то, что support-библиотеки изжили себя и нуждаются в переосмыслении.


    Команда разработчиков потратила несколько лет на выделение support-библиотек в отдельный небольшой проект, с которым можно работать используя Android Studio и Gradle. Разработка была перенесена в отдельную ветку, которая на днях стала публичной. Обновленные библиотеки получили название AndroidX. Еще одно важное отличие новых библиотек состоит в возможности независимого обновления. Гугл обещает бинарную совместимость в рамках одной мажорной версии, что позволит использовать в проекте recyclerview версии 1.0 и AppCompat версии 1.9 в одном проекте.


    На мой взгляд, это правильный и логичный шаг в развитии support-библиотек. Мне приходилось несколько раз сильно кастомизировать компоненты из support-библиотек, что приводило к необходимости создавать в моем проекте пакет com.android.support… для доступа к package-private классам/методам/полям.


    Сейчас я предлагаю вместе со мной “хакнуть” какую-нибудь библиотеку из семейства AndroidX. В качестве учебного пособия я выбрал CardView. Я собираюсь повлиять на поведение CardView не внося изменений в код, использующий его.


    Нам потребуется: Компьютер под управлением Linux или MacOS (Windows не поддерживается), Android SDK, опционально — Android Studio ( я использовал версию 3.1.3)


    Как же Windows?

    Для скачивания исходников рекомендуется использовать утилиту repo, которая недоступна для Windows. Исходники можно скачать и с использованием git'а, например, так: git clone --single-branch -b androidx-master-dev https://android.googlesource.com/platform/frameworks/support Однако, в данном случае не будут скачаны утилиты и скомпилированные зависимости. Я не проверял насколько это критично для сборки


    Для начала, я подготовил небольшой пример с использованием AndroidX.


    Основные моменты:


    Используем AndroidX


    def cardViewVer = '1.0.0-beta01'
    
    dependencies {
        implementation "androidx.cardview:cardview:$cardViewVer"
    }

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <androidx.cardview.widget.CardView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginBottom="32dp"
            android:layout_marginEnd="32dp"
            android:layout_marginLeft="32dp"
            android:layout_marginRight="32dp"
            android:layout_marginStart="32dp"
            android:layout_marginTop="32dp">
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Hello World!" />
    
        </androidx.cardview.widget.CardView>
    
    </FrameLayout>

    public class MainActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    }

    В итоге получаем следующее приложение:


    drawing

    Приступим к AndroidX


    Сперва, необходимо установить утилиту repo, созданную для упрощения работы с гитом в контексте андроида.


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


    mkdir androidX

    Устанавливаем утилиту


    сd androidX
    mkdir bin
    curl https://storage.googleapis.com/git-repo-downloads/repo > ./bin/repo
    chmod a+x ./bin/repo
    PATH={some_path}/androidX/bin/:$PATH

    Поясню, что мы сейчас сделали:
    В папке androidX создали папку repo, куда скачали файл по ссылке https://storage.googleapis.com/git-repo-downloads/repo, сделали файл исполняемым и добавили папку bin в PATH в рамках текущей сессии терминала.
    В моем случае последняя команда выглядела так: PATH=~/Work/projects/androidX/bin/:$PATH


    Качаем исходники AndroidX:


    Создаем в папку androidX/androidX-source и делаем ее текущей


    mkdir androidX-source
    cd androidX-source

    Инициализируем локальный репозиторий. Скачается примерно 16 мегабайт данных о существующих ветках в репозитории.


    repo init -u https://android.googlesource.com/platform/manifest -b androidx-master-dev

    В процессе имя и почта пользователя подтянется из глобального конфига гита, в моем случае, это выглядело так:


    Your identity is: Andrew <me@example.com>
    If you want to change this, please re-run 'repo init' with --config-name
    
    Если в конфиге нет этой информации, то имя и почта будут запрошены.
    Далее идет проверка форматированного вывода и запрос на его включение.
    Testing colorized output (for 'repo diff', 'repo status'):
      black    red      green    yellow   blue     magenta   cyan     white
      bold     dim      ul       reverse
    Enable color display in this user account (y/N)?

    На последний вопрос я ответил утвердительно.
    В конце получаем сообщение


    repo has been initialized in /Users/{user}/Work/projects/androidX/androidX-source

    Далее скачиваем непосредственно исходники (примерно 3 гигабайта)


    repo sync -j8 -c

    Скачанные исходники мы можем открыть в Android Studio или любом другом редакторе. Корневая папка gradle-проекта находится по адресу: androidX/androidX-source/frameworks/support/


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


    Открываем класс androidx.cardview.widget.RoundRectDrawable в модуле cardview
    Добавим безобидную шутку в метод onDraw


    canvas.drawText(“Hacked!”, 100, 100, paint);

    Полный патч


    Для проекте описана gradle-таска createArchive, которая соберет библиотеки androidX и разместит их в локальном мавен-репозитории. Адрес репозитория: androidX/androidX-source/out/host/gradle/frameworks/support/build/support_repo


    Для его использования необходимо указать путь в корневом билд-файле.


    maven { url 'androidX/androidX-source/out/host/gradle/frameworks/support/build/support_repo' }


    Обратите внимание, что собранная версия может быть новее чем в репозитории гугла. На момент написания статьи я собрал androidX библиотеку версии 1.0.0-rc01. Посмотреть версию собранной библиотеки можно в локальном мавен репозитории: androidX/androidX-source/out/host/gradle/frameworks/support/build/support_repo/androidx/cardview/cardview/maven-metadata.xml


    Обновленный пример


    Пересоберем наше приложение и увидим следующую картину:


    drawing

    AndroidX успешно пропатчен!


    Что это нам дает:


    • Мы можем фиксить критичные проблемы не ожидая апдейта от гугла. Кстати, команда AndroidX принимает пулл-реквесты.
    • Сильно кастомизировать androidX библиотеку.

    Ссылки по теме:
    Документация по support-библиотекам
    Пост в блоге разработчиков
    Инструкция по контрибьюции в AndroidX
    Трекер задач по AndroidX
    Исходники AndroidX

    • +20
    • 4,6k
    • 7

    Tinkoff.ru

    202,00

    IT’s Tinkoff.ru — просто о сложном

    Поделиться публикацией

    Похожие публикации

    Комментарии 7
      0
      >На мой взгляд, это правильный и логичный шаг в развитии support-библиотек.
      А на мой взгляд правильным и логичным шагом в развитии support-библиотек было бы вынесение всех support-библиотек в отдельные .apk, которые можно устанавливать и обновлять независимо друг от друга, и которыми смогли бы пользоваться все установленные в системе приложения.

      А то, что произошло сейчас ничем принципиально от того, что было не отличается, к сожалению — всё больше кусочков OS втаскивается внутрь приложения.
      Внутрь КАЖДОГО приложения.
      И это, к сожалению, приводит к безудержному росту размера .apk и используемой памяти (как дисковой, так и оперативной).

      Представьте, что у вас в системе половина бинарников слинкована статически, и с каждым днём их становится всё больше.
      Долго ли ваша машина продержится до вынужденного апгрейда? Год? Два?
        0
        Исходя из собственного опыта могу заметить, что в большинстве случаев контент многократно превосходит размер библиотек. Да и телефоны обновляются достаточно часто.
          0
          Может быть это и справедливо для всяких банков да гео-локационных справочников (тот же 2GIS или я.карты/я.пробки).
          Но вот приложениям категории «фонарик/заметки/кулинарная книга/etc.» это уже все только вредит — функционала «слеза кота», а размер как у кабана.
            0
            Ну так никто же не заставляет подключать support-библиотеки. Вполне можно писать и без них. Другой вопрос когда мы пытаемся дизайн из 2018 натянуть на устройство выпущенное в 2015 с Android 5 на борту.
            ЗЫ. изначально support появился как средство борьбы с фрагментацией. Не будет фрагментации — не нужен будет и support.
              0
              Ну у меня основной телефон 2013/2014-го, с v5 на борту как раз. Если бы не эта кривая модель «развития», то еще года три-четыре не было бы смысла менять, т.к. ЦП до сих пор за глаза, и памяти 2Гб даже хватает. NFC и прочие ништяки современности в нем были еще тогда.
              P.S. Только вчера этот фильм смотрел… вот же совпадение то :)
            0
            >Да и телефоны обновляются достаточно часто.
            Потому и обновляются слишком часто, что по другому никак.
            Если бы вместо этого порочного подхода был бы изначально принят модульный — мы бы до сих пор пользовались смартами с 1..2 гигабайтами памяти безо всяких проблем.
            Вообще, то, что сейчас происходит с мобильными устройствами мне лично кажется катастрофой. Рост показателей ради роста показателей, без реальной в них нужды. А программисты потом думают «6 гигов оперативки, зачем её экономить?», и спустя год-два из-за их приложений (написанных с таким подходом) 6 гигов уже становится мало. И появляются смарты с 8 гигабайтами оперативки, и через год-два цикл повторяется
            0
            >А на мой взгляд правильным и логичным шагом в развитии support-библиотек было бы вынесение всех support-библиотек в отдельные .apk, которые можно устанавливать и обновлять независимо друг от друга, и которыми смогли бы пользоваться все установленные в системе приложения.

            Ну примерно так сейчас работают play services.
            Play services общаются с приложениями через IPC (inter-process communication) на уровне простых комманд («покажи диалог логина», «покажи экран покупки», «дай список покупок»). Использовать UI-компоненты из play-services достаточно сложно (а support-библиотеки в основном состоят из UI-компонентов). Единственный пример, который я сейчас вспомнил — это youtube-плеер. Кстати, для использования play services в своем приложении тоже нужно использовать библиотеки.

            >А то, что произошло сейчас ничем принципиально от того, что было не отличается, к сожалению — всё больше кусочков OS втаскивается внутрь приложения.
            Внутрь КАЖДОГО приложения.

            С точки зрения разработчика изменения есть. Теперь не нужно синхронизировать версии всех support-библиотек.

            >И это, к сожалению, приводит к безудержному росту размера .apk и используемой памяти (как дисковой, так и оперативной).

            Тут вы немного сгущаете. Субъективно размер средней apk-шки за последние 4 года вырос раза в 2-3. Потребление оперативной памяти выросло примерно так же.

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

          Самое читаемое