Перепишите ссылку на метод в конкретном пакете, используя только dexlib2.

Я использую dexlib2 для перезаписи файлов dex. Мне нужно заменить конкретное имя класса на имя класса моей библиотеки, которое я включу в файл aar. Я использую для этого код ниже:

    DexFile dexFile = DexFileFactory.loadDexFile(filePath, Opcodes.forApi(apiLevel));
        DexRewriter dexRewriter = new DexRewriter(new RewriterModule() {

            @Override
            public Rewriter<MethodReference> getMethodReferenceRewriter(Rewriters rewriters) {
                return new Rewriter<MethodReference>() {
                    @Override
                    public MethodReference rewrite(MethodReference value) {

                        if (value.getDefiningClass().equals("Ljava/util/Calendar;")
                                && value.getName().equals("getInstance")) {
                            System.out.println("method Ref class:" + value.getDefiningClass());

                            ImmutableMethodReference methodRef = new ImmutableMethodReference(
                                    "Lcom/mylib/ICalendar;", value.getName(),
                                    value.getParameterTypes(), value.getReturnType());
                            return methodRef;
                        }
                        return value;
                    }
                };
            }

        });
        DexFile rewrittenDexFile = dexRewriter.rewriteDexFile(dexFile);
        DexFileFactory.writeDexFile(filePath, rewrittenDexFile);

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


person chikka.anddev    schedule 26.03.2017    source источник


Ответы (1)


Да. Вы можете переопределить getClassDefRewriter и добавить туда свой фильтр.

DexRewriter dexRewriter = new DexRewriter(new RewriterModule() {

    @Nonnull @Override public Rewriter<ClassDef> getClassDefRewriter(@Nonnull Rewriters rewriters) {
        return new ClassDefRewriter(rewriters) {
            @Nonnull @Override public ClassDef rewrite(@Nonnull ClassDef classDef) {
                if (classDef.getType().startsWith("Lcom/my/package/")) {
                    return super.rewrite(classDef);
                }
                return classDef;
            }
        };
    }

    @Override
    public Rewriter<MethodReference> getMethodReferenceRewriter(Rewriters rewriters) {
        return new Rewriter<MethodReference>() {
            @Override
            public MethodReference rewrite(MethodReference value) {

                if (value.getDefiningClass().equals("Ljava/util/Calendar;")
                        && value.getName().equals("getInstance")) {
                    System.out.println("method Ref class:" + value.getDefiningClass());

                    ImmutableMethodReference methodRef = new ImmutableMethodReference(
                            "Lcom/mylib/ICalendar;", value.getName(),
                            value.getParameterTypes(), value.getReturnType());
                    return methodRef;
                }
                return value;
            }
        };
    }
});
person JesusFreke    schedule 26.03.2017
comment
Еще раз спасибо за быстрый ответ! Я использовал его. Я столкнулся с проблемой после обновления файла dex. Чтобы проверить, я попытался преобразовать его в банку с помощью dex2jar, и он выдает ошибку при преобразовании (d2j не удается перевести: java.lang.RuntimeException: \r\n\tat com.googlecode.dex2jar.ir.ts.NewTransformer.transform (НовыйТрансформер.java:134)) - person chikka.anddev; 26.03.2017
comment
Не знаю. Похоже проблема с dex2jar :) - person JesusFreke; 27.03.2017
comment
Я могу это использовать. но после замены одного из имен классов с помощью getTypeRewriter происходит сбой моего apk. Говорит NoSuchMethodError. В основном я создал одну библиотеку, которая добавляется как aar, у которой есть фактический класс, для которого я изменил тип. - person chikka.anddev; 28.03.2017
comment
Ну, существует ли метод, для которого он выдает ошибку? :) - person JesusFreke; 28.03.2017
comment
У меня есть один класс Say IDate, который расширяет Date, и я заменил тип Date на IDate. Я получаю сообщение об ошибке, когда код имеет simpleDateFormat.format(IDate);. Я пробовал в коде вручную. Это разрешено, но при использовании в файле dex. Выдает ошибку. - person chikka.anddev; 28.03.2017
comment
Если вы вызываете метод в интерфейсе, вы должны использовать invoke-interface, а не invoke-virtual. - person JesusFreke; 28.03.2017
comment
SimpleDateFormat - это класс Android SimpleDateFormat, поэтому он не является интерфейсом. Единственное, в чем я могу сомневаться, так это в том, что я обновляю dex своим пользовательским классом, которого еще нет. но после обновления dex я объединяю свою библиотеку с этим классом. так это может быть проблемой? - person chikka.anddev; 28.03.2017