Java反射处理库的更改

11

好的,我有一个安卓应用程序,并开始创建一个插件系统供开发人员编写内容提供者来生成不同的内容,我不会详细说明整个过程,但所有东西都像这样正常工作:

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

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

3)回到安卓应用程序,我可以加载由开发人员创建的.jar文件(在将classes.dex添加到jar文件后),并使用安卓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的即时运行解决了类似的问题。请尝试阅读更多相关信息,例如这里 - Alex Lipov
据我所知,@Alex即时运行是一个开发工具,不能用于生产环境,甚至我怀疑它是否应该使用。我说的是在单独的.dex文件中加载插件,根据加载的插件重写应用程序的dex对我来说似乎是一个很大的安全风险。 - Amr El Aswar
@Alex 是的,我明白你的意思,感谢你的建议。但问题是,我已经成功完成了所有的工作,唯一引起问题的部分是addon dex有一个类的副本,而这个类也在Android项目中。如果它们之间有任何差异,就会导致问题。 - Amr El Aswar
你可以提供一个简单的示例来说明你的问题吗?包括初始apk、附加dex和修改后的apk,只需要相关部分即可,无需完整解决方案。 - Alex Lipov
@Alex,你所说的修改版apk指的是什么? - Amr El Aswar
显示剩余2条评论
1个回答

2
我的解决方案并没有解决问题,而是确保它永远不会发生。你所描述的问题类似于经典的服务器-客户端问题。你有一个服务器(在你的情况下是你正在开发的应用程序),还有客户端(由开发人员编写的插件)。你可以定义一个接口,其中包含许多函数,并以二进制结构传递数据。从流量/解析的角度来看,这将更加高效,但是每当你更改服务器上的API时,你都必须更新所有客户端(否则可能会出现崩溃或其他问题)。
因此,为了解决这个问题,在服务器-客户端上许多人选择使用HTTP调用和描述数据的JSON对象。虽然这种方式不太高效,但它允许添加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不再识别该类,而只会忽略更改。但是在这种情况下,这种方法不起作用,因此我确信有办法完成它。 - Amr El Aswar
JSON的替代方案是传递Bundle对象。也许这样会更少引起混淆。重要的是要避免强制转换,因为对象可能不正确。 - Doron Yakovlev Golani
我可以传递一个序列化对象,然后在插件端反序列化它,再使用相同的SerialVersionUID进行强制转换,但是用户不知道他们接收到了哪个对象,因此反序列化过程也会变得混乱。 - Amr El Aswar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接