Java 如何防止客户端在Android库中看到内部私有类?
我有一个带几个软件包的图书馆- 让我们说Java 如何防止客户端在Android库中看到内部私有类?,java,android,jar,android-library,Java,Android,Jar,Android Library,我有一个带几个软件包的图书馆- 让我们说 a包 b包 在a包内,我有一个公共a_类 在b包内,我有公共b_类 a_类使用b_类 我需要从中生成一个库,但我不希望客户端看到b_类 我所知道的唯一解决方案是将我的可理解的包扁平化为单个包,并对b_类使用默认包访问。 还有别的办法吗?可能使用接口或某种形式的设计模式???如果我理解正确,您要求发布库供第三方使用,而不披露部分源代码?如果您可以使用这种情况,则可能会混淆您的库。默认情况下,所有内容都将被排除/模糊处理,除非您指定了要排除模糊处理/模糊处理
a包
b包 在a包内,我有一个公共a_类
在b包内,我有公共b_类
a_类使用b_类 我需要从中生成一个库,但我不希望客户端看到b_类 我所知道的唯一解决方案是将我的可理解的包扁平化为单个包,并对b_类使用默认包访问。
还有别的办法吗?可能使用接口或某种形式的设计模式???如果我理解正确,您要求发布库供第三方使用,而不披露部分源代码?如果您可以使用这种情况,则可能会混淆您的库。默认情况下,所有内容都将被排除/模糊处理,除非您指定了要排除模糊处理/模糊处理的内容。如果您希望在客户端无法访问代码的情况下分发代码的[部分],则意味着客户端也将无法执行代码。:-O 因此,您只有一个选择:将代码的合理部分放入公共服务器,并分发一个代理来访问它,这样您的代码将保留在服务器中并在服务器中执行,客户机仍然能够通过代理执行代码,但无需直接访问它 根据代码的复杂程度,可以使用servlet、webservice、RMI对象或简单的TCP服务器
这是我能想到的最安全的方法,但它也值得付出代价:除了使系统复杂化之外,它还会为每个远程操作引入网络延迟,这可能会很大程度上取决于性能要求。此外,您还应该对服务器本身进行安全保护,以避免黑客入侵。如果您已经有了一个可以利用的服务器,这可能是一个很好的解决方案。如果您拒绝将代码移动到单独的受控服务器,那么您所能做的就是在尝试使用API时阻碍客户机程序员。让我们开始将良好实践应用于您的设计:
- 让它成为非公开的
- 将其公共API提取到新的公共接口:
公共接口MyInterface{…}
- 创建公共工厂类以获取该接口类型的对象
公共类MyFactory
{
公共MyInterface createObject();
}
public class MyFactory
{
public MyInterface createObject(Macguffin parameter);
}
那么,什么是Macguffin
?它是您必须在应用程序中定义的新接口,至少有一种方法:
public interface Macguffin
{
public String dummyMethod();
}
但不提供此接口的任何可用实现。在需要提供Macguffin
对象的代码的每个地方,通过匿名类创建它:
或者,更高级的是,通过动态代理对象,因此即使客户端程序员敢于反编译代码,也不会找到此实现的“.class”文件
你从中得到了什么?基本上是劝阻程序员不要使用需要未知、未记录、无法理解的对象的工厂。工厂类应该只关心不接收null对象,调用dummy方法并检查返回值是否为null(或者,如果您想要更高的安全级别,请添加一个未记录的密钥规则)
因此,此解决方案依赖于对API的细微混淆,以阻止客户端程序员直接使用它。Macguffin接口及其方法的名称越模糊越好
我需要从中生成一个库,但我不希望客户端看到b_类。我所知道的唯一解决方案是将我的可理解的包扁平化为单个包,并对b_类使用默认包访问。还有别的办法吗
是,将b_类
包设为私有(默认访问),并通过反射将其实例化,以便在a_类
中使用
因为您知道完整的类名,所以可以反射式加载该类:
Class<?> clz = Class.forName("b.b_class")
调用构造函数以获取您的b_类
实例:
Object o = con.newInstance();
好极了,现在您有了b_类的一个实例。但是,不能对对象的实例调用b_类的方法,因此有两个选项:
使用反射来调用b_类
的方法(虽然不是很有趣,但是很简单,如果只有几个方法和几个参数,可能还可以)
让b_类
实现一个您不介意客户看到的接口,并将您的b_类
实例投射到该接口(我怀疑您可能已经有了这样的接口?)李>
您肯定希望使用选项2来最小化您的痛苦,除非它让您再次回到原点(用您不想向客户机公开的类型污染名称空间)
关于全面披露,请注意以下两点:
1) 与直接实例化和调用相比,使用反射有(很小的)开销。如果您强制转换到一个接口,您只需支付实例化的反射成本。在任何情况下,这都不是问题,除非您在一个紧密的循环中进行成千上万次调用
2) 没有什么可以阻止已确定的客户端查找类名并执行相同的精简操作
Constructor<?> con = clz.getDeclaredConstructor();
con.setAccessible(true);
Object o = con.newInstance();