目錄
1、方法一
1.1、在AndroidStudio中檢視
1.2、樣碼
1.3、輸出結果(簡單易讀)
2、方法二
2.1、kotlin編譯成class所在目錄
2.2、Kotlin樣碼
2.3、注意
2.4、Javap -public 輸出結果
2.5、javap -p -private
2.6、Javap -c 輸出結果
3、方法三
3.1、Jadx反編譯工具
1、方法一
1.1、在AndroidStudio中檢視
第一步:選擇你要檢視你的kotlin檔案,然後點選Tools-->Kotlin-->Show Kotlin Bytecode
第二步:點選左上角的 Decompile 按鈕就會彈出你想要的class源碼
1.2、樣碼
class TestMain {
public val msg1 = "類中的變量"
private val msg2 = "類中的變量"
companion object {
val msg3 = "伴生對象的變量"
}
}
val msg4 = "Kotlin檔案中的變量"
fun sayHello(msg: String) {
println("msg=$msg")
}
fun main() {
val msg5 = "我要看你的class檔案"
sayHello(msg5)
}
1.3、輸出結果(簡單易讀)
public final class TestMainKt {
@NotNull
private static final String msg4 = "Kotlin檔案中的變量";
@NotNull
public static final String getMsg4() {
return msg4;
}
public static final void sayHello(@NotNull String msg) {
Intrinsics.checkParameterIsNotNull(msg, "msg");
String var1 = "msg=" + msg;
boolean var2 = false;
System.out.println(var1);
}
public static final void main() {
String msg5 = "我要看你的class檔案";
sayHello(msg5);
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
2、方法二
利用指令行 javap [option] *.class 指令
子指令 | 輸出資訊 |
---|---|
-l | 輸出行和變量的表 |
-public | 隻輸出公共的方法和成員 |
-protected | 隻輸出public和protected類和成員 |
-package | 隻輸出包,public和protected類和成員,這是預設情況 |
-p -private | 輸出所有類和成員 |
-s | 輸出内部類型簽名 |
-c | 對代碼進行反彙編。 eg:類中每一個方法内,包含 java 位元組碼的指令 |
-verbose | 輸出棧大小,方法參數的個數 |
-costants | 輸出靜态 final 常量 |
2.1、kotlin編譯成class所在目錄
編譯後的class檔案在app--tmp--kotlin-classes--自己的包名 内
2.2、Kotlin樣碼
class TestMain {
public val msg1 = "類中的變量"
private val msg2 = "類中的變量"
companion object {
val msg3 = "伴生對象的變量"
}
}
val msg4 = "Kotlin檔案中的變量"
fun sayHello(msg: String) {
println("msg=$msg")
}
fun main() {
val msg5 = "我要看你的class檔案"
sayHello(msg5)
}
2.3、注意
在這裡需要注意,但我們在一個Kotlin檔案中定義了一個類和類外部的一些變量和方法的時候,它在編譯後會生成兩個class檔案。
如下:一個TestMain的類class ,還有一個是TestMainKt.class檔案
2.4、Javap -public 輸出結果
Javap -public 輸出公共的方法和成員
這裡分别輸出了上面TestMain.kt檔案生成的兩個class檔案的公共的方法和成員變量
javap -public TestMainKt.class
Compiled from "TestMain.kt"
public final class com.yobo.yobo_kotlin.TestMainKt {
public static final java.lang.String getMsg2();
public static final void sayHello(java.lang.String);
public static final void main();
public static void main(java.lang.String[]);
}
javap -public TestMain.class
Compiled from "TestMain.kt"
public final class com.yobo.yobo_kotlin.TestMain {
public static final com.yobo.yobo_kotlin.TestMain$Companion Companion;
public final java.lang.String getMsg1();
public com.yobo.yobo_kotlin.TestMain();
public static final java.lang.String access$getMsg3$cp();
}
2.5、javap -p -private
javap -p -private 顯示所有的類和成員
javap -p -private TestMainKt.class
public final class com.yobo.yobo_kotlin.TestMainKt {
private static final java.lang.String msg4;
public static final java.lang.String getMsg4();
public static final void sayHello(java.lang.String);
public static final void main();
public static void main(java.lang.String[]);
static {};
}
2.6、Javap -c 輸出結果
Javap -c 對代碼進行反彙編。 eg:類中每一個方法内,包含 java 位元組碼的
可以看到雖然是把我們整個class檔案進行了反編譯,但是可讀性不是很好,這時候我們就推薦第二種方法。
public final class com.yobo.yobo_kotlin.TestMainKt {
public static final java.lang.String getMsg2();
Code:
0: getstatic #13 // Field msg2:Ljava/lang/String;
3: areturn
public static final void sayHello(java.lang.String);
Code:
0: aload_0
1: ldc #17 // String msg
3: invokestatic #23 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V
6: new #25 // class java/lang/StringBuilder
9: dup
10: invokespecial #29 // Method java/lang/StringBuilder."<init>":()V
13: ldc #31 // String msg=
15: invokevirtual #35 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
18: aload_0
19: invokevirtual #35 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: invokevirtual #38 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
25: astore_1
26: iconst_0
27: istore_2
28: getstatic #44 // Field java/lang/System.out:Ljava/io/PrintStream;
31: aload_1
32: invokevirtual #50 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
35: return
public static final void main();
Code:
0: ldc #56 // String 我要看你的class檔案
2: astore_0
3: aload_0
4: invokestatic #58 // Method sayHello:(Ljava/lang/String;)V
7: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #54 // Method main:()V
3: return
static {};
Code:
0: ldc #8 // String Kotlin檔案中的變量
2: putstatic #13 // Field msg2:Ljava/lang/String;
5: return
}
3、方法三
3.1、Jadx反編譯工具
先給出工具的GitHub位址,可以按照自己喜歡的方式安裝并檢視功能文檔:
https://github.com/skylot/jadx
下載下傳zip包解壓後,檔案目錄如下:
輕按兩下jadx-gui就可以打開圖形界面:
工具支援apk、dex、jar、aar等格式的檔案,可以通用File - Open file選擇檔案或者直接将檔案拖進視窗中,可以算得上一鍵反編譯了,非常簡單易用,對比dex2jar & jd-gui組合,完勝。
AndroidStudio寫的每個class或者kotlin檔案都會編譯成單獨的dex。圖中紅色框 0 是java代碼, 1 是kotlin代碼,我們可以将這些dex直接拖入到jadx反編譯工具中檢視。
下圖是随手丢進去的一個apk,可以看到不止代碼, 包中的資源也被解出來了。