Modify the class files in AAR and Jar

hi,2021

foreword

Recently, I helped a colleague solve a difficult problem, and the process of digging along the way was quite interesting. Document it here. (PS: The main reason is that the project is relatively large, and we only have Androidthe development authority for part of the business-side code of the entire project. Therefore, some conventional means of solving problems cannot be used.)

question

Requirements: Webpage H5and nativeinteraction, save base64图片.

Problem: Using the existing encapsulated Hybridprotocol, it was found in the final integration test that some mobile phones could not be saved successfully.

  • During debugging, it was found H5that the original protocol format was used to call the new protocol, and nativethe logs and breakpoints of the new protocol registered on the business side could not be triggered.
  1. Suspected the problem of the original protocol format, when H5 uses the original protocol format to call the new protocol that already exists on the line, it is found that the nativecall can be successful, and this problem is ruled out;
  2. Suspecting the parameter problem in the new protocol, H5 removes the parameter in the new protocol and finds that it can be called to the nativenew protocol implementation. It is guessed that the problem may be caused by the protocol parameters;
    1. Find the place where the protocol call is triggered through the breakpoint, that is, H5the nativeplace where the data is communicated. It is found that the current Hybridprotocol uses the nativeend-to-end replication onJsPromptmethod and the interception JavaScriptmethod prompt().
    2. Change the new protocol parameters back and call again. The breakpoint found that the transmitted data was truncated in the nativeend-to-end replication method, and the data parsing failed and could not be forwarded to the next service test.onJsPrompt

Problems

The original communication bridge Hybrid协议used in the project is now encountering **a major flood (larger data)** and there is an obstacle problem.复写prompt方法

solution selection

  1. Change the picture in the format to H5the picture in the format;base64http

    The picture is originally H5drawn, and the interactive experience of the client downloading after uploading is too poor;

  2. Our business side implements our own set of Hybridprotocols;

  3. Let the project's infrastructure department modify the existing Hybridagreement;

    The bug discovered at night will require closed testing tomorrow. It is difficult to complete the change of cross-departmental infrastructure within 24 hours.

In the end, we chose the second option, implementing a set of Hybridprotocols ourselves.

solution realization

  1. Get WebViewcalls addJavascriptInterfacethe method to H5add JSobjects to the environment.
  2. The development JStool allows it to call the new JScommunication method according to the old protocol format.
  3. Parse the obtained data and throw it to onJsPromptthe wrapper class object that originally processed the data in the method.

If we can change all the project code, then there is no difficulty in this solution. The difficulty is that we only have H5the outermost shell of this page Activity, and the encapsulation WebViewdoes not expose the method we want to the outside world. So the implementation of the third step of the program has problems.

We have two solutions to this problem:

Hybrid-Base64-project.jpg

  1. This time, two sets of logic are made by injecting the communication protocol JSof the object Hybridand the original Hybridprotocol of the project;
  2. Call methods hookin other original classes through multiple black technology;dispatch

If that was the case, there would be no article for this article.

Well, after so much rambling, I finally started to get to the point. I don't know how many students plan to continue reading.

We can take all AARthe files in the project, think about whether we can modify the source code to provide what we want API, and then solve the problem by upgrading AARthe version . Well, the focus of this article has come out to modify the class file in AAR .

Modify the class file in AAR

Option One

First delete AARthe ones you want to modify class, and repackage them as new ones AAR. The project depends on the new version AAR, and then create an identical class under the corresponding package of the project.

  1. Decompile the content of the original classfile and copy it to the newly created class and run it directly.
  2. Decompile the original classfile content and copy it to the newly created class. Finally, recompile the generated one classand add it AARto repackage to generate a new one AAR.

If the class is obfuscated, then this solution is basically abolished. Because there are a large number of packages with the same class name in the decompiled classcontent, it is impossible to confirm that the class used in this call is still a package during this recompilation.

As an example, the following structure is often seen after obfuscation.

com.xx.a
com.xx.a.a

When writing the following code, it will prompt that athere is no class under the class a, instead of alooking for the class under the package a.

a ma = new com.xx.a.a();

Option II

aop-asm.JPEG

According to the above figure, it can be seen that this scheme is for aspect programming. We only need to add a method or two to a class to solve the problem of limited access. Considering the difficulty of the current problem we choose Javassist. Because the actual bytecode manipulation in Javassistthe source code level APIis easier to use, it can be used without deep knowledge of the specification.ASMJVM

Javassist official document

jarPackage download address Github:javassist

//需要添加的方法
//public void executeJSCmd(String var1) {
    
    
//    if (this.mActionDispatcher != null) {
    
    
//        Message var2 = this.mActionHandler.obtainMessage(0);
//        var2.obj = var1;
//        this.mActionHandler.sendMessage(var2);
//    }
//}
//需要操作的class的类名:com.xxx.android.web.webview.BaseWebChromeClient
public class Test {
    
    
    public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException {
    
    
        ClassPool classPool = ClassPool.getDefault();
        // 必须将class文件放在这个工程编译后的class文件中,路径也对应起来
        CtClass ctClass = classPool.get("com.xxx.android.web.webview.BaseWebChromeClient");
        CtMethod newmethod = CtNewMethod.make("public void executeJSCmd(String message) { if (this.mActionDispatcher != null) { android.os.Message msg = this.mActionHandler.obtainMessage(0); msg.obj = message; this.mActionHandler.sendMessage(msg); } }",ctClass);
        ctClass.addMethod(newmethod);
        ctClass.writeFile();
    }
}

It should be noted that, for example, the method we added involves other classes that need to write the full path android.os.Message, and the package related to this class jarmust also be added to the running environment (you can also put the class file of this class in the compiled project class file directory), otherwise an error will be reported during execution.

Exception in thread "main" javassist.CannotCompileException: [source error] no such class: android.os.Message
	at javassist.CtNewMethod.make(CtNewMethod.java:78)
	at javassist.CtNewMethod.make(CtNewMethod.java:44)
	at com.test.pattern.Test.main(Test.java:13)

important point

When replacing or deleting, jarit classis best not to decompress and then use the named package. When I Maxuse the command jarto package there will be a .DS_Storefile. BetterZipThe compression & decompression tool I use is very convenient to add and delete in jarthe package without decompression .class

The article is all told here, if you have other needs to communicate, you can leave a message ! !

If you want to read more articles by the author, you can check out my personal blog and public account:
Revitalize Book City

Guess you like

Origin blog.csdn.net/stven_king/article/details/113188698