【问题标题】:Java reflection handling library changesJava 反射处理库更改
【发布时间】:2017-04-29 01:59:34
【问题描述】:

好的,所以我有一个 Android 应用程序,我开始为该应用程序创建一个插件系统,以便开发人员可以编写内容提供程序,然后该应用程序可以使用这些内容提供程序来生成不同的内容,我不会完成整个过程,但一切正常,就像所以:

1) 我创建了一个名为com.myaddonlib 的库,我在我的项目中导入了这个库,其中有一个接口和不同的对象。

2) 现在开发人员可以在他的端创建一个简单的 Java 项目,导入库com.myaddonlib,并在他的主类上实现接口,该接口具有从库返回不同对象的方法。

3) 回到 android 应用程序,我可以加载开发人员创建的 .jar 文件(在将 classes.dex 添加到 jar 文件之后),使用 android DexClassLoader 我可以像这样加载实现的接口:

DexClassLoader classloader = new DexClassLoader(jarFilePath, tempDirectory, null, context.getClass().getClassLoader());     
Class classToLoad = classloader.loadClass("com.apackage.Addon");

其中Addon 是插件开发人员创建的类,它实现了位于名为com.apackage 的包中的库中的接口。 然后,我可以将库 com.myaddonlib 中的接口转换为 classToLoad 的新实例,并调用插件开发人员实现的函数。

现在的问题是我决定更新插件库并从类中删除其中一个变量,这意味着插件的类现在与更新后的库中的类(在应用程序中使用)不同。即使未使用更改的变量,也会导致应用程序崩溃而没有任何错误。只是两个类不同的事实(即使唯一的区别只是缺少变量)会导致某些故障。现在这不是一个容易解释的过程,所以我会理解,鉴于我的英语不好,有些人难以理解。 我的问题是我需要知道如何避免由于两端之一库的更改而导致的崩溃。还有java在这种情况下是如何处理对象变化的

【问题讨论】:

  • 假设插件更新是在运行时完成的,Android Studio 的即时运行解决了类似的问题。尝试阅读有关它的更多信息,例如here
  • @Alex Instant run 是据我所知的开发工具,不能在生产中使用,我什至怀疑它应该,我说的是在单独的 .dex 文件中加载插件,如上所述,根据加载的插件重写应用程序 dex 在我看来是一个很大的安全风险
  • 我并不是说即时运行是解决您上述问题的方法。我只是说即时运行解决了在运行时重新加载类的问题,这与您正在寻找的类似(据我所知) - 通过查看它的工作原理,您希望能够获取构建您自己的解决方案的想法。
  • @Alex 是的,我明白你的意思,谢谢你的提议,但问题是我已经设法完成了所有事情,唯一导致问题的部分是插件 dex 有一份android 项目中的类,如果其中任何一个有差异,则会导致问题。
  • 您是否有机会提供一个简单的示例来说明您的问题(初始 apk、插件 dex 和修改后的 apk)?不需要完整的解决方案,只需相关部分即可。

标签: java android reflection dex


【解决方案1】:

我的解决方案并没有解决问题,而是确保它永远不会发生。您描述的问题类似于经典的服务器-客户端问题。您有一个服务器(在您的情况下是您正在开发的应用程序)和客户端(由开发人员编写的插件)。您可以定义具有许多功能的接口并以二进制结构传递数据。从流量/解析的角度来看,这会更有效,但是每当您更改服务器上的 API 时,您都必须更新所有客户端(否则可能会发生崩溃或其他问题)。

因此,为了解决服务器-客户端上的这个问题,许多人选择使用带有描述数据的JSON 对象的 HTTP 调用。虽然这种方式效率较低,但它允许添加 API 并同时支持多个客户端版本。

在 Android 中使用这种方法非常简单。定义一个具有两个函数和一个接口的 API:

public String sendDataToLibrary(String jsonString) {
   // Parse data, perform operation and return a JSON string as the result
}

public interface GetDataFromLibrary {
   String onDataFromLibrary(String jsonString);
}

public void init startLibrary(GetDataFromLibrary callback) {
   // Set callback in library and call it whenever you have data that needs to be sent out from the library asynchronously 
}

如你所见,如果你实现了这个接口,你可以在库和插件之间传递任何数据,它永远不会改变,所以不会发生崩溃。一个改进可以是强制传递版本号以允许库支持多版本)。

【讨论】:

  • 您好,感谢您的建议,将数据作为 JSON 传递会导致混淆,我认为反射的问题在于,当插件尝试强制转换类时,插件从应用程序接收对象时从库到该对象,并且两端的类的定义不同,它会崩溃。使用 Serializable 时,如果我们在变量中设置相同的 serialVersionUID 更改不会导致 Java 不再识别该类而只是忽略更改,但这在这种情况下不起作用,所以我确信有办法完成它
  • JSON 的替代方法是传递一个 Bundle 对象。也许这会不那么令人困惑。重要的是要避免转换,因为对象可能不正确。
  • 我可以传递一个序列化对象并在插件端 snd 上对其进行反序列化,然后使用相同的 SerialVersionUID 对其进行转换,但用户又不知道他们收到了哪个对象,因此反序列化过程也会令人困惑。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-15
  • 1970-01-01
  • 1970-01-01
  • 2016-12-09
相关资源
最近更新 更多