ByteBuddy Android - 创建并调用具有特定名称的方法,该方法直接调用另一个方法
ByteBuddy Android - Create and call a method with a certain name that directly calls another method
这是对该主题的后续(尽管不同)问题:
我正在尝试在 Android 上向 Crashlytics 发送非崩溃错误报告,感谢 Rafael Winterhalter,我现在实现了它们在 Crashlytics UI 中的不同行中显示。这样做的要求是为每个问题类型发送不同的异常子class。
现在看起来像下面的屏幕截图。
下一个问题是,它仍然没有一眼就真正显示出实际的异常类型是什么。相反,它只显示发送错误的函数名称。现在了解了 Byte Buddy 的魔力后,我想 - 也许甚至可以在自定义异常 subclass 中创建一个静态函数,它直接调用 Crashlytics.logException
函数。我已经看到可以使用拦截器 class(然后从那里调用代码),但我想 Crashlytics 将始终在该拦截器中显示函数名称。
是否可以创建名称为 issueType
的静态方法并让它直接调用 Crashlytics.logException
?
到目前为止,这是我更新的代码:
public static void craslyticsRecordError(String issueType, String errorMsg)
{
// byte buddy needs a private directory
File filesDir = GameApplication.getAppContext().getFilesDir();
String dirPath = filesDir.getAbsolutePath() + File.separator + "ByteBuddy";
File byteBuddyPrivateDirectory = new File(dirPath);
if (!byteBuddyPrivateDirectory.exists())
{
byteBuddyPrivateDirectory.mkdirs();
}
GameLog.d("ByteBuddyDir:" + byteBuddyPrivateDirectory);
try
{
// dynamically create an exception with 'issueType' as its class name and also create method
// that has this name, so that Crashlytics will show that name
Class<? extends Exception> dynamicType = new ByteBuddy()
.subclass(Exception.class)
.name(issueType)
.defineMethod(issueType, void.class, Ownership.STATIC, Visibility.PUBLIC)
.withParameters(Throwable.class)
.intercept(MethodCall.invoke(Crashlytics.class.getMethod("logException", Throwable.class)))
.make() // line of crash
.load(Fabric.class.getClassLoader(), new AndroidClassLoadingStrategy.Wrapping(byteBuddyPrivateDirectory))
.getLoaded();
Exception e = dynamicType.getConstructor(String.class).newInstance(errorMsg);
Method method = Crashlytics.class.getMethod(issueType, Exception.class);
method.invoke(null, e);
}
catch (Exception e1)
{
Exception e = new Exception(issueType + "-" + errorMsg);
Crashlytics.logException(e);
e1.printStackTrace();
}
}
崩溃堆栈跟踪:
java.lang.IllegalStateException: public static void com.crashlytics.android.Crashlytics.logException(java.lang.Throwable) does not take 0 arguments
at net.bytebuddy.implementation.MethodCall$Appender.apply(MethodCall.java:1998)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyCode(TypeWriter.java:620)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyBody(TypeWriter.java:609)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod.apply(TypeWriter.java:526)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForCreation.create(TypeWriter.java:4159)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1633)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:174)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:155)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:2559)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:2661)
at org.utils.Fabric.craslyticsRecordError(Fabric.java:69)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:323)
at android.os.Looper.loop(Looper.java:143)
at android.app.ActivityThread.main(ActivityThread.java:7224)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
是的,这当然是可能的,文档甚至包含一个示例。您可以按如下方式定义方法:
new ByteBuddy()
.subclass(Exception.class)
.defineMethod("issueType", void.class, Ownership.STATIC, Visibility.PUBLIC)
.withParameters(Exception.class)
.intercept(MethodCall.invoke(Crashalytics.getMethod("logException"))
.withArgument(0));
这将定义一个方法
public static void issueType(Exception e) {
Crashalytics.logException(e);
}
在您生成的 class.
中
这是对该主题的后续(尽管不同)问题:
我正在尝试在 Android 上向 Crashlytics 发送非崩溃错误报告,感谢 Rafael Winterhalter,我现在实现了它们在 Crashlytics UI 中的不同行中显示。这样做的要求是为每个问题类型发送不同的异常子class。
现在看起来像下面的屏幕截图。
Crashlytics.logException
函数。我已经看到可以使用拦截器 class(然后从那里调用代码),但我想 Crashlytics 将始终在该拦截器中显示函数名称。
是否可以创建名称为 issueType
的静态方法并让它直接调用 Crashlytics.logException
?
到目前为止,这是我更新的代码:
public static void craslyticsRecordError(String issueType, String errorMsg)
{
// byte buddy needs a private directory
File filesDir = GameApplication.getAppContext().getFilesDir();
String dirPath = filesDir.getAbsolutePath() + File.separator + "ByteBuddy";
File byteBuddyPrivateDirectory = new File(dirPath);
if (!byteBuddyPrivateDirectory.exists())
{
byteBuddyPrivateDirectory.mkdirs();
}
GameLog.d("ByteBuddyDir:" + byteBuddyPrivateDirectory);
try
{
// dynamically create an exception with 'issueType' as its class name and also create method
// that has this name, so that Crashlytics will show that name
Class<? extends Exception> dynamicType = new ByteBuddy()
.subclass(Exception.class)
.name(issueType)
.defineMethod(issueType, void.class, Ownership.STATIC, Visibility.PUBLIC)
.withParameters(Throwable.class)
.intercept(MethodCall.invoke(Crashlytics.class.getMethod("logException", Throwable.class)))
.make() // line of crash
.load(Fabric.class.getClassLoader(), new AndroidClassLoadingStrategy.Wrapping(byteBuddyPrivateDirectory))
.getLoaded();
Exception e = dynamicType.getConstructor(String.class).newInstance(errorMsg);
Method method = Crashlytics.class.getMethod(issueType, Exception.class);
method.invoke(null, e);
}
catch (Exception e1)
{
Exception e = new Exception(issueType + "-" + errorMsg);
Crashlytics.logException(e);
e1.printStackTrace();
}
}
崩溃堆栈跟踪:
java.lang.IllegalStateException: public static void com.crashlytics.android.Crashlytics.logException(java.lang.Throwable) does not take 0 arguments
at net.bytebuddy.implementation.MethodCall$Appender.apply(MethodCall.java:1998)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyCode(TypeWriter.java:620)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyBody(TypeWriter.java:609)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod.apply(TypeWriter.java:526)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForCreation.create(TypeWriter.java:4159)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1633)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:174)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:155)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:2559)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:2661)
at org.utils.Fabric.craslyticsRecordError(Fabric.java:69)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:323)
at android.os.Looper.loop(Looper.java:143)
at android.app.ActivityThread.main(ActivityThread.java:7224)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
是的,这当然是可能的,文档甚至包含一个示例。您可以按如下方式定义方法:
new ByteBuddy()
.subclass(Exception.class)
.defineMethod("issueType", void.class, Ownership.STATIC, Visibility.PUBLIC)
.withParameters(Exception.class)
.intercept(MethodCall.invoke(Crashalytics.getMethod("logException"))
.withArgument(0));
这将定义一个方法
public static void issueType(Exception e) {
Crashalytics.logException(e);
}
在您生成的 class.
中