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

OSCHINA-MIRROR/miqt-WandFix

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

WandFix

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

27 декабря 2019 года 14:58:43 Проект перешёл к использованию методов hotfix, применяя метод замены родительского ClassLoader вместо предыдущего рефлексивного замены классов.

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

При загрузке класса используется принцип двойной проверки, то есть сначала BootCLassLoader пытается загрузить данный класс, если он отсутствует, то загружает PathClassLoader.

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

Схема работы

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

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

Условия использования:

Преимущества и недостатки:

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

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

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

Затем добавьте зависимости в :app:

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

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

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

Создайте новый класс активити, который наследуется от ProxyActivity, и добавьте аннотацию @BindProxy.

// Бinds the proxy class
@BindProxy(clazz = TextActivityProxy.class)
// Must inherit from 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);
        ...
    }
    
    ...
}

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

Реализация горячего исправления для одного классового файла

public class MainActivity extends AppCompatActivity implements Wand.MotorListener {
```    ```java
    @InjectObject(
            // full class name
            value = "com.miqt.demo.presenter.AppPresenterImpl",
            // setting parental trust
            // during development it is recommended to use PROJECT, prioritizing the use of local libraries.
            // upon release of the project, it should be changed to NEVER, prioritizing the use of hotfix package libraries.
            level = ParentalEntrustmentLevel.NEVER)
    AppPresenter ap;
    ```    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // можно инициализировать один раз в application
        Wand.get().init(this).listener(this);
    }

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

        // также можно инициализировать объект без использования аннотации для внедрения
        // 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 по пути к файлу плагина
// требуется разрешение на чтение/запись файлов
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 добавьте к активностям для привязки специального прокси.### Настройка ProGuard

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

-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).

Если вам понравился данный проект, то нажмите кнопку "Star" ( ̄▽ ̄)*

## Проблемы, возникшие во время разработки и существующие проблемы- [x] При `targetVersion` > 25 активность-прокси не работает (решено)
- [x] При наличии анонимных внутренних классов в пакете горячих исправлений возникает ошибка `java.lang.NoClassDefFoundError` (решено)
- [x] При использовании `findViewById` в активности-прокси иногда контролы не находятся или возникают ошибки преобразования типов (решено)
- [ ] Обработка ProGuard пока недостаточно хороша, поскольку из-за использования рефлексии при активации ProGuard могут возникнуть ошибки `ClassNotFoundException`, но если не использовать ProGuard, защита исходного кода будет недостаточной. Однако у меня есть несколько идей решения этой проблемы, которые еще не были реализованы.
    - [ ] Первый вариант: анализ файла `.app.build.outputs.mapping.debug.mapping.txt` для получения отображения между исходными классами, методами и именами и их зашифрованными версиями, затем поиск соответствующего класса в коде.
    - [ ] Второй вариант: использование шифрования 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