接兔兔國際sdk ane
充值界面選擇兔幣充值就會閃退,
觀察logcat ,NoSuchMethodError: com.tutu.common.a.b.getContext 原來是因為沒有方法找不到
04-19 10:10:54.224: E/AndroidRuntime(20315): FATAL EXCEPTION: main 04-19 10:10:54.224: E/AndroidRuntime(20315): Process: com.tutusdk.global.demo, PID: 20315 04-19 10:10:54.224: E/AndroidRuntime(20315): java.lang.NoSuchMethodError: com.tutu.common.a.b.getContext 04-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