当前位置: 首页 > news >正文

松江网站设计wordpress+菜单大小

松江网站设计,wordpress+菜单大小,最近发生的热点事件,外包网站价格问题 我的问题是什么#xff1f; 在桥接类 UnityBridgeActivity 中处理不同 unity 版本调用 mUnityPlayer.destroy(); 闪退问题。 闪退日志如#xff1a; 闪退日志说在 UnityBridgeActivity中找不到类型为 UnityPlayer 的属性 mUnityPlayer。 我们知道#xff0c;Android… 问题 我的问题是什么 在桥接类 UnityBridgeActivity 中处理不同 unity 版本调用 mUnityPlayer.destroy(); 闪退问题。 闪退日志如 闪退日志说在 UnityBridgeActivity中找不到类型为 UnityPlayer 的属性 mUnityPlayer。 我们知道Android unity 游戏开发中通常只有一个 Activity 为游戏主页面且该 Activity 需要继承自 UnityPlayerActivity unity 的实现内部有一个重要类是 UnityPlayer 通过它进一步调用接口渲染游戏等。 在我们的 sdk 中 Activity 之间的关系大概是这样也就是在桥接类中是可以访问父类的成员 mUnityPlayer 的。 接下来介绍的两个不同版本运行表现不一样。 1、正常版本 UnityPlayerActivity例如 unity 版本 2021 这个版本引擎导出的 unity-class.jar 是这样的UnityPlayerActivity 具有成员 mUnityPlayer 类型是UnityPlayer 类型。 UnityPlayer 从 unity 导出的抽象类不同 unity 版本可能有不同实现 public abstract class UnityPlayer {public void destroy() {//... ...} }package com.unity3d.player;public class UnityPlayerActivity extends Activity {protected UnityPlayer mUnityPlayer; }这个版本打包运行是不会闪退的正常包我们看 sdk 内调用 destroy() 的大概实现如下 UnityBridgeActivitysdk 桥接类 public class UnityBridgeActivity extends UnityPlayerActivity {private void quitGame(){//other ... ...mUnityPlayer.destroy();} }我们查看此段代码的字节码通过 Android studio 的 ASM 插件可方便查阅 mUnityPlayer 字段名com/unity3d/player/UnityPlayerActivity 字段所在类Lcom/unity3d/player/UnityPlayer; 字段类型INVOKEVIRTUAL com/unity3d/player/UnityPlayer.destroy ()V 调用字段的 destroy 方法 这段字节码是正确的没毛病能运行正常这段代码被编译、打包进 sdk 被外部使用。 private invokerUnityV1()VALOAD 0GETFIELD com/unity3d/player/UnityPlayerActivity.mUnityPlayer : Lcom/unity3d/player/UnityPlayer;INVOKEVIRTUAL com/unity3d/player/UnityPlayer.destroy ()VRETURNMAXSTACK 1MAXLOCALS 12、闪退版本 UnityPlayerActivity例如 unity 版本 2022 这个版本引擎导出的 unity-class.jar 是这样的UnityPlayerActivity 具有相同成员 mUnityPlayer但是类型是 UnityPlayerForActivityOrService与上述不同。 package com.unity3d.player;public class UnityPlayerActivity extends Activity {protected UnityPlayerForActivityOrService mUnityPlayer; }UnityPlayerForActivityOrService package com.unity3d.player;public class UnityPlayerForActivityOrService extends UnityPlayer{}问题出现 已知sdk 编译得到的字节码明确获取的 mUnityPlayer 字段类型是 UnityPlayer GETFIELD com/unity3d/player/UnityPlayerActivity.mUnityPlayer : Lcom/unity3d/player/UnityPlayer; 但是我们发现在 unity 版本 2022字段 mUnityPlayer 的类型是 UnityPlayerForActivityOrService这里就和闪退日志对上了明确抛出这个版本中没有 UnityPlayer 类型的这个字段。 解决 字段名称是不变的只是类型发生了变化导致的闪退那么我们是否可以针对特定的版本执行不同的分支获取正确类型的 mUnityPlayer 1、如何解决 可以在 Android 打包 transform 过程中定位桥接类 UnityBridgeActivity.class 调用 destroy 方法的地方并读取作为字节数组输入 ASM利用 ASM 字节码操作修改 mUnityPlayer 的类型也就是修改指令。 从 GETFIELD com/unity3d/player/UnityPlayerActivity.mUnityPlayer : Lcom/unity3d/player/UnityPlayer; 修改为 GETFIELD com/unity3d/player/UnityPlayerActivity.mUnityPlayer : Lcom/unity3d/player/UnityPlayerForActivityOrService; 编码、测试 为了方便修改、测试可以在桥接类单独抽出这个方法作为新的分支解决 unity 2022 版本的兼容问题。 private void invokerUnityV2022() {super.mUnityPlayer.destroy(); }通过 ASM 把这个方法修改为这样即可却别仅在于 mUnityPlayer 的类型。 private invokerUnityV2022()VALOAD 0GETFIELD com/unity3d/player/UnityPlayerActivity.mUnityPlayer : Lcom/unity3d/player/UnityPlayerForActivityOrService ;INVOKEVIRTUAL com/unity3d/player/UnityPlayer.destroy ()VRETURNMAXSTACK 1MAXLOCALS 1两个版本、两个分支 收集当前类对应的所有字段 package com.primer.unitybridge;import java.lang.reflect.Field; import java.util.List;/*** 创建者村长* 时间2024/5/22 11:58*/ public class FieldInfo {public ListField fields;public String className;public FieldInfo(String classname, ListField fields) {this.className classname;this.fields fields;} }final String superClassname getClass().getSuperclass().getName();public void invokeUnityDestroy(String superClassname) {final String unityClassName com.unity3d.player.UnityPlayer;final String unityClassName2 com.unity3d.player.UnityPlayerForActivityOrService;try {Class? clazz Class.forName(superClassname);ListFieldInfo fieldInfoList getAllFields(clazz);for (FieldInfo fieldInfo : fieldInfoList) {if (fieldInfo.fields null || fieldInfo.fields.size() 0) {continue;}for (Field field : fieldInfo.fields) {//获取字段数据类型不同类型走不同分支String fieldType field.getType().getName();if (unityClassName.equals(fieldType)) {//原先版本保留可以直接这样调用因为 sdk 内部字节码对应是正确的super.mUnityPlayer.destroy();} else if (unityClassName2.equals(fieldType)) {//兼容 unity 2022 版本抽出单独的方法方便编码、测试invokerUnityV2022();}}}} catch (ClassNotFoundException e) {LogUtil.d(TAG, invokeUnityDestroy 1 e);} catch (SecurityException e) {LogUtil.d(TAG, invokeUnityDestroy 2 e);} catch (IllegalArgumentException e) {LogUtil.d(TAG, invokeUnityDestroy 3 e);}}private void invokerUnityV2022() {super.mUnityPlayer.destroy();}private static ListFieldInfo getAllFields(Class? clazz) {ListFieldInfo fieldInfos new ArrayList();while (clazz ! null) {ListField fields new ArrayList();fields.addAll(Arrays.asList(clazz.getDeclaredFields()));fieldInfos.add(new FieldInfo(clazz.getName(), fields));clazz clazz.getSuperclass();}return fieldInfos;}2、ASM 基于 groovy 编写 gradle 插件干预 class 文件生成具体看 asm 相关代码。 UnityClassvisitor package com.primer.plugin.common.asm;import static org.objectweb.asm.Opcodes.ALOAD; import static org.objectweb.asm.Opcodes.GETFIELD; import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; import static org.objectweb.asm.Opcodes.RETURN;import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor;public class UnityClassvisitor extends ClassVisitor {public UnityClassvisitor(int api, ClassVisitor classVisitor) {super(api, classVisitor);}Overridepublic void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {super.visit(version, access, name, signature, superName, interfaces);}Overridepublic MethodVisitor visitMethod(int access, String name, String descriptor, String signature,String[] exceptions) {MethodVisitor mv super.visitMethod(access, name, descriptor, signature, exceptions);//找到该类中的 invokerUnityV2022 方法if (name.equals(invokerUnityV2022) descriptor.equals(()V)) {// 生成新的方法体generateNewBody(mv);// 情况原来的方法体return null;}return mv;}/*** 原方法体* private invokerUnityV1()V* ALOAD 0* GETFIELD com/unity3d/player/UnityPlayerActivity.mUnityPlayer :* Lcom/unity3d/player/UnityPlayer;* INVOKEVIRTUAL com/unity3d/player/UnityPlayer.destroy ()V* RETURN* MAXSTACK 1* MAXLOCALS 1** param mv*/private void generateNewBody(MethodVisitor mv) {//这段代码可以通过 Android studio asm 插件轻松获取mv.visitCode();mv.visitVarInsn(ALOAD, 0);mv.visitFieldInsn(GETFIELD, com/unity3d/player/UnityPlayerActivity, mUnityPlayer,Lcom/unity3d/player/UnityPlayerForActivityOrService;);mv.visitMethodInsn(INVOKEVIRTUAL, com/unity3d/player/UnityPlayer, destroy, ()V, false);mv.visitInsn(RETURN);mv.visitMaxs(1, 1);mv.visitEnd();}Overridepublic void visitEnd() {super.visitEnd();} } 找到需要修改的类返回修改后的字节数组在 transform 阶段覆盖原先的字节数组使其生成新的 class 文件并打包到 jar 中。 public static byte[] byUnityClassVisitor(byte[] originBytes, String originClassFileName) {//找到 UniWbActivity.class 调用 mUnityPlayer 的类if (!com/primer/unitybridge/UniWbActivity.class.equals(originClassFileName)) {return null;}if (originBytes null || originBytes.length 0) {return null;}ClassReader classReader new ClassReader(originBytes);ClassWriter classWriter new ClassWriter(ClassWriter.COMPUTE_FRAMES);UnityClassvisitor clazzVisitor new UnityClassvisitor(Opcodes.ASM9, classWriter);classReader.accept(clazzVisitor, ClassReader.SKIP_DEBUG);byte[] bytes classWriter.toByteArray();if (bytes ! null || bytes.length ! 0) {return bytes;}return null;}
http://www.w-s-a.com/news/699748/

相关文章:

  • 选服务好的网站建设亚洲砖码砖专区2022
  • 网站快速查找wordpress 悬停 图片 文字
  • 网站续费 多久想自己做网站该学些什么
  • 可以自己做网站wordpress英文写作插件
  • 国外可以做会员网站的网站怎么查百度竞价关键词价格
  • 新站网站建设亚马逊关键词
  • 电商网站前端架构设计上海市建设工程安全生产协会网站
  • 东莞企业免费模版网站建设一般网站维护要多久
  • 著名建筑设计网站常州制作网站价格
  • 食品营销型网站广东省广州市白云区
  • 如何做网站哪个站推广描述对于营销型网站建设很重要飘红效果更佳
  • 济阳做网站公司99企业邮箱888
  • 国贸做网站的公司能接做网站的活的网站
  • 淮南建设厅网站上杭县建设局网站
  • 东莞做网站公司首选!西安注册公司费用
  • 做网站包括什么卖水果网站模板
  • 扬州网站建设外包wordpress 文章评分
  • 网站建设网站多少钱公司名字大全列表
  • 设计企业网站内容wordpress 投稿者 权限
  • seo网站推广免费价格低的成语
  • 做网站建设销售辛苦吗专题页是什么
  • 做网站的软件名字全拼wordpress可以上传文件吗
  • 建品牌网站公司关于asp_sql网站开发的书籍
  • 建网站公司营销型网站建设wordpress自定义登录页
  • 泉州市住房和城乡建设局网站淘宝店网站怎么做
  • 企业网站建设费未付款怎样挂账长春网站制作专业
  • 深圳找网站建设邹城市建设局网站
  • 长春火车站停运了吗网站开发概要设计
  • 网站开发表格整体页面居中网站域名详解
  • 漕泾网站建设赢展网站建设