1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/miqt-WandFix

Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

WandFix

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

27 декабря 2019 года 14:58:43 Этот проект изменил методы горячей фиксации, заменив предыдущий метод замены классов с помощью рефлексии на использование Hack ClassLoader mParent.

Как известно, в Android обычно имеются два ClassLoader: BootClassLoader и PathClassLoader.

При загрузке класса, на основе принципа двойной проверки, сначала BootClassLoader пытается загрузить этот класс, если он не найден, то загрузка происходит с помощью PathClassLoader.

Основной метод замены проекта заключается в том, чтобы вставить между BootClassLoader и PathClassLoader пользовательский WandClassLoader. Таким образом, когда проект загружает класс, он сначала пытается загрузить его с помощью WandClassLoader, что позволяет достичь цели замены без использования рефлексии.

Схема

О проектеWandFix — это библиотека, которая позволяет использовать аннотации для внедрения объектов реализации, основанная на Java APT+рефлексии+ClassLoader, поэтому не требуется использование new для инициализации объектов. Кроме того, она может динамически загружать указанные .apk, .dex, .jar, .class файлы, используя аннотации для установки приоритета загрузки, чтобы выбрать источник класса для внедрения. Таким образом, этот проект позволяет классам, аннотированным, получать способность горячей фиксации!Для использования WandFix достаточно добавить аннотации к переменным для внедрения объектов. Функция горячей фиксации реализуется путём замены пакета горячей фиксации, чтобы каждый раз загружаемый объект был последним изменённым, что позволяет достичь цели горячей фиксации. Конечно, если вы не хотите использовать функцию горячей фиксации и просто хотите удобно внедрять объекты, вы можете просто добавить аннотации, так как если соответствующий класс реализации не найден в пакете горячей фиксации, будет попытка загрузить его из локальной части проекта, что гарантирует стабильность программы.

Пример работы проекта: (обновлено 12 апреля 2019 года 17:23:29: для использования этого проекта в реальных проектах, я также написал простой проект, который может быть хорошим примером использования этого проекта. Перейти)demo预览

Преимущества:

  • Подобно Butter Knife, можно напрямую добавлять аннотации @InjectObject("полное имя реализации") к переменным для привязки к реализациям в пакете горячей фиксации.
  • Не требуется закрывать приложение для применения пакета горячей фиксации.
  • Лучше всего работает в сочетании с паттерном MVP.
  • Можно самостоятельно определять классы, подлежащие горячей фиксации.
  • Можно настроить алгоритм шифрования Dex для защиты файлов Dex.
  • Можно использовать аннотации для отключения родительского делегирования для отдельных объектов.
  • Динамическое проксирование Activity функция, добавлена 19 февраля 2019 года.
  • Поддерживает загрузку внешних макетов, иконок, цветов и других ресурсных файлов.## Способ использования:

В файл build.gradle проекта добавьте:

allprojects {
	repositories {
		...
		maven { url 'https://jitpack.io' }
	}
}

Затем добавьте зависимости в файл build.gradle модуля app:

annotationProcessor  'com.github.miqt.WandFix:wand-compiler:v1.3.6'
implementation  'com.github.miqt.WandFix:wand:v1.3.6'

Реализация динамического прокси для Activity

Динамическое прокси для Activity означает, что все действия одного Activity передаются в прокси-класс для обработки. Прокси-класс по сути является обычным классом, объектом, поэтому мы можем использовать DexClassloader для замены, что и реализует динамическое прокси.

Сначала создайте новый Activity, унаследованный от ProxyActivity, и добавьте аннотацию @BindProxy

// Привязка прокси-класса
@BindProxy(clazz = TextActivityProxy.class)
// Обязательно унаследован от ProxyActivity
public class TextActivity extends ProxyActivity {
    // Здесь ничего не нужно писать
}

Затем создайте новый класс, унаследованный от ActivityProxy, и реализуйте методы прокси

// Каждый прокси-класс должен быть настроен
@AddToFixPatch
public class TextActivityProxy extends ActivityProxy {
    public TextActivityProxy(ProxyActivity acty) {
        super(acty);
    }
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        mActy.setContentView(R.layout.activity_hello);
        ...
    }
    ...
}

Просто запустите этот Activity с помощью startActivity(new Intent(this, TextActivity.class));, и прокси начнет работать. Впоследствии, если изменится прокси-класс, можно отправить изменения через сборку пакета для горячей перезагрузки.

Реализация горячей перезагрузки для отдельного класса

public class MainActivity extends AppCompatActivity implements Wand.MotorListener {
    @InjectObject(
            // полное имя класса
            value = "com.miqt.demo.presenter.AppPresenterImpl",
            // установка родительского доверия
            // во время разработки рекомендуется использовать PROJECT, чтобы приоритет был у локальных классов.
            // при выпуске проекта следует изменить на NEVER, чтобы приоритет был у классов из пакета горячей перезагрузки.
            level = ParentalEntrustmentLevel.NEVER)
    AppPresenter ap;```java
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // можно инициализировать один раз в приложении
        Wand.get().init(this).listener(this);
    }

    public void getStr(View view) {
        // для использования аннотации для вставки объекта, необходимо вызвать эту строку
        ClassInstall.inject(this);
        // или конструктор с параметрами
        // Map<String, Object[]> pramHouse = new HashMap<>();
        // pramHouse.put("com.miqt.demo.presenter.AppPresenterImpl", new Object[]{"hello"});
        // ClassInstall.inject(this, pramHouse);

        // также можно инициализировать объект без использования аннотации
        // ap = ObjectFactory.make("com.miqt.demo.presenter.AppPresenterImpl" /*, параметры конструктора */);
        // ap = ObjectFactory.make(AppPresenterImpl.class /*, параметры конструктора */);

        String str = ap.getStr();
        Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
    }
}

Загрузка ресурсов из плагина APK

        // сначала создаем PluginResources по пути к файлу плагина APK
        // требуется разрешение на чтение и запись файлов
        PluginResources manager = new PluginResources(context, pluginApkPath);

        // загрузка цветовых ресурсов
        int id = manager.getId("text_color", "color");
        int color = manager.getResources().getColor(id, context.getTheme());
        textView.setTextColor(color);

        // загрузка разметки
        View main_layout = manager.getLayout("activity_main");
        // сначала создаем PluginResources по пути к файлу плагина APK
        // требуется разрешение на чтение и запись файлов
        PluginResources manager = new PluginResources(context, pluginApkPath);

        // загрузка цветовых ресурсов
        int id = manager.getId("text_color", "color");
        int color = manager.getResources().getColor(id, context.getTheme());
        textView.setTextColor(color);

        // загрузка разметки
        View main_layout = manager.getLayout("activity_main");
```### Описание использования связанных аннотаций и их функции

1. @InjectObject добавьте к членам переменных для внедрения объекта в эти переменные.
2. @AddToFixPatch добавьте к классам без параметров, чтобы указать, что эти классы связаны с горячими исправлениями. В процессе компиляции и сборки пакета классы, помеченные этим аннотированием, будут добавлены в список сборки. Если классы имеют аннотацию @InjectObject, то они могут быть добавлены без этого аннотирования.
3. @BindProxy добавьте к классам активности для привязки к определённому агенту активности.### Настройка кода для обфускации

Если проект настроен на обфускацию, необходимо скопировать следующий код в файл конфигурации обфускации:

-keep class com.miqt.wand.** {;} -keep class * {@com.miqt.wand.anno.InjectObject ;} -keep @com.miqt.wand.anno.AddToFixPatch class * {;} -keep @com.miqt.wand.anno.BindProxy class * {*;}


## Другое
Долгий путь начинается с первого шага, приветствуем ваши вопросы и предложения.

[Как создать и применить пакет горячих исправлений](https://github.com/miqt/WandFix/wiki/Как-создать-и-применить-пакет-горячих-исправлений)

Для получения дополнительной информации перейдите на [Wiki](https://github.com/miqt/WandFix/wiki)

Если вам понравился этот проект, оставьте звёздочку ( ̄▽ ̄)~*

## Проблемы, возникшие во время разработки и существующие проблемы- [x] При targetVersion > 25 активность-агент не работает (решено)
- [x] При наличии анонимных внутренних классов в пакете горячих исправлений возникает ошибка java.lang.NoClassDefFoundError (решено)
- [x] При использовании findViewById в активности-агенте иногда контролы не находятся или возникают ошибки преобразования типов (решено)
- [ ] Обработка обфускации пока не на высоте, из-за использования рефлексии, если код обфусцирован, возникает ошибка ClassNotFoundException, а если не обфусцирован, то защита исходного кода не гарантируется. Однако у меня есть несколько идей по решению этой проблемы, которые ещё не были реализованы.
    - [ ] Идея 1: С помощью анализа файла .\app\build\outputs\mapping\debug\mapping.txt получить отображение между исходными классами, методами и именами и их обфусцированными версиями, и использовать это для поиска соответствующих классов в коде.
    - [ ] Идея 2: Реализовать оболочку для dex, так как пакет горячих исправлений фактически представляет собой файл dex, а использование пользовательской оболочки может частично предотвратить декомпиляцию.

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

Описание недоступно Развернуть Свернуть
MIT
Отмена

Обновления

Пока нет обновлений

Участники

все

Язык

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://api.gitlife.ru/oschina-mirror/miqt-WandFix.git
git@api.gitlife.ru:oschina-mirror/miqt-WandFix.git
oschina-mirror
miqt-WandFix
miqt-WandFix
master