記一次使用修改位元組碼的方法解決java.lang.NoSuchMethodError,位元組碼

來源:互聯網
上載者:User

記一次使用修改位元組碼的方法解決java.lang.NoSuchMethodError,位元組碼

接兔兔國際sdk ane

儲值介面選擇兔幣儲值就會閃退,

觀察logcat ,NoSuchMethodError: com.tutu.common.a.b.getContext 原來是因為沒有方法找不到

04-19 10:10:54.224: E/AndroidRuntime(20315): FATAL EXCEPTION: main04-19 10:10:54.224: E/AndroidRuntime(20315): Process: com.tutusdk.global.demo, PID: 2031504-19 10:10:54.224: E/AndroidRuntime(20315): java.lang.NoSuchMethodError: com.tutu.common.a.b.getContext04-19 10:10:54.224: E/AndroidRuntime(20315):     at com.tutu.common.a.b.a(TutuAlertDialog.java:78)04-19 10:10:54.224: E/AndroidRuntime(20315):     at com.tutu.common.a.b.onCreateView(TutuAlertDialog.java:66)04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.support.v4.app.Fragment.performCreateView(Fragment.java:1786)04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:947)04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1126)04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:739)04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1489)04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:454)04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.os.Handler.handleCallback(Handler.java:733)04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.os.Handler.dispatchMessage(Handler.java:95)04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.os.Looper.loop(Looper.java:136)04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.app.ActivityThread.main(ActivityThread.java:5113)04-19 10:10:54.224: E/AndroidRuntime(20315):     at java.lang.reflect.Method.invokeNative(Native Method)04-19 10:10:54.224: E/AndroidRuntime(20315):     at java.lang.reflect.Method.invoke(Method.java:515)04-19 10:10:54.224: E/AndroidRuntime(20315):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)04-19 10:10:54.224: E/AndroidRuntime(20315):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:609)04-19 10:10:54.224: E/AndroidRuntime(20315):     at dalvik.system.NativeStart.main(Native Method)

可以用附件中的jar包練習,下載的是zip 解壓之後就有jar包。用 jd-gui 反編譯找到b class, 介紹一個更好用的反編譯工具:apktoolbox,下載:http://www.52pojie.cn/thread-429318-1-1.html

package com.tutu.common.a;import android.graphics.drawable.ColorDrawable;import android.os.Bundle;import android.support.v4.app.DialogFragment;import android.view.LayoutInflater;import android.view.View;import android.view.View.OnClickListener;import android.view.ViewGroup;import android.widget.Button;import android.widget.TextView;import com.feng.android.i.e;import com.feng.android.i.f;/* compiled from: TutuAlertDialog */public class b extends DialogFragment {    private TextView a;    private Button b;    private Button c;    private String d;    private String e;    private String f;    private String g;    private a h;    /* compiled from: TutuAlertDialog */    public interface a {        void c(String str);        void c_(String str);    }    public void onCreate(Bundle bundle) {        super.onCreate(bundle);    }    public static b a(String str, String str2, String str3, String str4, a aVar) {        b bVar = new b();        Bundle bundle = new Bundle();        bundle.putString("left_text", str);        bundle.putString("right_text", str2);        bundle.putString("dialog_tips", str3);        bundle.putString("dialog_tag", str4);        bVar.setArguments(bundle);        bVar.a(aVar);        return bVar;    }    public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle bundle) {        getDialog().requestWindowFeature(1);        getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(0));        View inflate = layoutInflater.inflate(e.c(getActivity(), "tutu_alert_dialog_layout"), viewGroup, false);        getDialog().getWindow().setGravity(17);        if (getArguments() != null) {            this.d = getArguments().getString("left_text");            this.e = getArguments().getString("right_text");            this.f = getArguments().getString("dialog_tips");            this.g = getArguments().getString("dialog_tag");        }        a(inflate);        setCancelable(false);        return inflate;    }    public void a(a aVar) {        this.h = aVar;    }    private void a(View view) {        this.b = (Button) view.findViewById(e.a(getActivity(), "tutu_alert_dialog_ignore_btn"));        this.c = (Button) view.findViewById(e.a(getActivity(), "tutu_alert_dialog_recharge_btn"));        this.a = (TextView) view.findViewById(e.a(getContext(), "tutu_alert_dialog_tips"));        if (!f.c(this.d)) {            this.b.setText(this.d);        }        if (!f.c(this.e)) {            this.c.setText(this.e);        }        if (!f.c(this.f)) {            this.a.setText(this.f);        }        this.b.setOnClickListener(new OnClickListener(this) {            final /* synthetic */ b a;            {                this.a = r1;            }            public void onClick(View view) {                if (this.a.h != null) {                    this.a.h.c_(this.a.g);                }                this.a.dismiss();            }        });        this.c.setOnClickListener(new OnClickListener(this) {            final /* synthetic */ b a;            {                this.a = r1;            }            public void onClick(View view) {                if (this.a.h != null) {                    this.a.h.c(this.a.g);                }                this.a.dismiss();            }        });    }}

 

問題就出在標紅的位置,通過這個 

http://stackoverflow.com/questions/36116606/nosuchmethoderrorcom-android-app-fragment-getcontext-in-android

知道, 新版的sdk才支援getContext方法,但是adobe air sdk 要跟進比較慢,沒有該方法,要改成 getActivity

因為這是第三方sdk , 沒有原始碼, 只能修改 class檔案。 

google 一番 如何修改位元組碼, 找到幾篇文章。 放在最後。

 

下載 jclasslib ,安裝。開啟jclasslib bytecode viewer 用於查看 b.class 檔案的位元組碼

解壓jar包, 將 com/tutu/common/a檔案夾內的b.class 檔案 拖拽進bytecode viewer 

 

根據上面反編譯出來的源碼,我們要修改的地方在   private void a(View view)  這個方法中,展開左邊的Methods, 一個個看圖中名稱為a的方法, 觀察右邊的Access flags, 如果不是private的迅速跳過,是的話觀察右邊Descriptor ,這裡面是參數列表。 覺得像的就展開它, 選中 [0]Code, 觀察右邊的byte code

 

 

 

圖中 22行 就是要找的 getContext。 滑鼠點擊前面的 #56 , 跳的下面這張圖

 

 

看到使用的 劃紅線的部分是 #80  再回到 bytecode中 , 看13行 getActivity的地方時 #54, 滑鼠點擊它, 跳到下面這張圖

 

看到 劃紅線的部分是 #78 , 滑動左邊的列表, 發現這個東西是在Constant Pool 分類下。 好下面編代碼修改位元組碼, 將指向#80 改成指向 #78

在eclipse中建立一個java project。

進入jclasslib 安裝目錄, 進入 modules/data/src/main/java ,拷貝 org 及其內容到 java project src 目錄下

 

建立一個 App 類,放main方法

import java.io.DataInput;import java.io.DataInputStream;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import org.gjt.jclasslib.io.ClassFileWriter;import org.gjt.jclasslib.structures.CPInfo;import org.gjt.jclasslib.structures.ClassFile;import org.gjt.jclasslib.structures.InvalidByteCodeException;import org.gjt.jclasslib.structures.MethodInfo;import org.gjt.jclasslib.structures.constants.ConstantMethodrefInfo;import org.gjt.jclasslib.structures.constants.ConstantNameAndTypeInfo;public class App {    public static void main(String[] args) throws InvalidByteCodeException, IOException {         String filePath = "C:/Users/fp/Documents/goalPlatformClientV1/ANE/tutu/package/Android-ARM/b.class";              FileInputStream fis = new FileInputStream(filePath);              DataInput di = new DataInputStream(fis);              ClassFile cf = new ClassFile();              cf.read(di);                          CPInfo[] infos = cf.getConstantPool();                                      MethodInfo[] ms = cf.getMethods();            MethodInfo m = ms[5];            //            System.out.println(m.getAccessFlags());//            System.out.println(m.getAccessFlagsVerbose());//            System.out.println(m.getName());//            System.out.println(m.getNameIndex());//            System.out.println(m.getDescriptor());//            System.out.println(m.getDescriptorIndex());//            AttributeInfo[] getAttributes = m.getAttributes();//            System.out.println(m.getAttributes());                                    ConstantMethodrefInfo uInfo = (ConstantMethodrefInfo) infos[56]; //剛剛那裡是CONSTANT_Methodref_info所以這裡要用這個              ConstantNameAndTypeInfo nt = uInfo.getNameAndTypeInfo();            String s = String.format("%s\n%s\n%s\n%s", nt.getName(), nt.getTag(), nt.getTagVerbose() ,  nt.getVerbose());            System.out.println(s);            uInfo.setNameAndTypeIndex(78);              infos[56] = uInfo;        //            int count = infos.length;  //            for (int i = 0; i < count; i++) {  //                if (infos[i] != null) {  //                    System.out.print(i);  //                    System.out.print(" = ");  //                    System.out.print(infos[i].getVerbose());  //                    System.out.print(" = ");  //                    System.out.println(infos[i].getTagVerbose());  //                    if (i == 160) {//剛剛找到的是21位置  //                        ConstantUtf8Info uInfo = (ConstantUtf8Info) infos[i]; //剛剛那裡是CONSTANT_Utf-8_info所以這裡要用這個  ////                        System.out.println("xxxxxxxxxxxxxxxxxxxx");////                        uInfo.setString("getActivity");  // 如果用這種方式直接修改string ,不行, Name and Type 後面的type 還是Landroid/content/Context////                        infos[i] = uInfo;  //                    }  //                }  //            }              //這種方式也可以,一樣的      /*      if(infos[count] != null) {                 ConstantUtf8Info uInfo = (ConstantUtf8Info) infos[i]; //剛剛那裡是CONSTANT_Utf-8_info所以這裡要用這個                 uInfo.setBytes("baidu".getBytes());                 infos[count] = uInfo;             }*/                            cf.setConstantPool(infos);              fis.close();              File f = new File(filePath);              ClassFileWriter.writeToFile(f, cf);      }}

 

用於練手的附件:

http://files.cnblogs.com/files/lonkiss/java.library.tutu.zip 

解壓之後有個jar包。 部落格園不讓直接上傳jar包

參考資料:

直接修改別人jar包裡面的class檔案 工具:jclasslib - hexin373的專欄 - 部落格頻道 - CSDN.NET http://blog.csdn.net/hexin373/article/details/6669813

如何利用JClassLib修改.class檔案 - “羊習習”的專欄 - 部落格頻道 - CSDN.NET http://blog.csdn.net/betterandroid/article/details/14520667

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.