繁体   English   中英

如何防止客户端看到 Android 库中的内部私有类?

[英]How to prevent client from seeing internal private classes in Android library ?

我有一个包含多个包的库-

让我们说
套餐一;
包 b;

包内 a 我有公共 a_class
在包 b 里面我有公共 b_class
a_class 使用 b_class。

我需要从中生成一个库,但我不希望客户端看到 b_class。

我所知道的唯一解决方案是将我精美易懂的包扁平化为单个包,并为 b_class 使用默认包访问。 还有另一种方法吗? 也许使用接口或某种形式的设计模式?

如果您拒绝将代码移动到单独的受控服务器,那么您所能做的就是在尝试使用您的 API 时阻碍客户端程序员 让我们开始将良好实践应用到您的设计中:

  1. 让您的包裹像现在一样井然有序。
  2. 对于您想要“隐藏”的每个类:

    • 使其非公开。
    • 将其公共 API 提取到一个新的公共接口:

    public interface MyInterface {...}

    • 创建一个公共工厂类以获取该接口类型的对象。

    public class MyFactory { public MyInterface createObject(); }

到目前为止,您的包现在是松散耦合的,并且实现类现在是私有的(正如您已经说过的良好实践所宣扬的那样)。 尽管如此,它们仍然可以通过接口和工厂使用。

那么,如何避免“陌生人”客户端执行您的私有 API? 接下来是一个创造性的、有点复杂但有效的解决方案,基于阻碍客户端程序员:

修改您的工厂类:向每个工厂方法添加一个新参数:

public class MyFactory
{
    public MyInterface createObject(Macguffin parameter);
}

那么,什么是Macguffin 这是您必须在应用程序中定义的新接口,至少有一个方法:

public interface Macguffin
{
    public String dummyMethod();
}

不提供此接口的任何可用实现。 在您需要提供Macguffin对象的代码的每个地方,通过匿名类创建它:

MyFactory.getObject(new Macguffin(){
    public String dummyMethod(){
        return "x";
    }
});

或者,更高级的是,通过动态代理对象,因此即使客户端程序员敢于反编译代码,也不会找到此实现的“.class”文件。

你从中得到什么? 基本上是劝阻程序员不要使用需要未知、未记录、无法理解的对象的工厂。 工厂类应该只关心不接收空对象,并调用虚拟方法并检查返回值它也不为空(或者,如果您想要更高的安全级别,请添加未记录的密钥规则)。

因此,此解决方案依赖于对 API 的微妙混淆,以阻止客户端程序员直接使用它。 Macguffin 接口及其方法的名称越模糊越好。

我需要从中生成一个库,但我不希望客户端看到 b_class。 我所知道的唯一解决方案是将我精美易懂的包扁平化为单个包,并为 b_class 使用默认包访问。 还有另一种方法吗?

是的,使b_class包私有(默认访问)并通过反射实例化它以在a_class使用。

既然你知道完整的类名,反射加载类:

Class<?> clz = Class.forName("b.b_class")

找到要调用的构造函数:

Constructor<?> con = clz.getDeclaredConstructor();

通过使其可访问来允许自己调用构造函数:

con.setAccessible(true);

调用构造函数来获取你的b_class实例:

Object o = con.newInstance();

b_class ,现在你有了一个b_class的实例。 但是,您不能在Object的实例上调用b_class的方法,因此您有两个选择:

  1. 使用反射来调用b_class的方法(没什么好玩的,但足够简单,如果你只有几个参数很少的方法可能没问题)。
  2. b_class实现一个您不介意客户端看到的接口并将您的b_class实例b_class为该接口(我怀疑您可能已经拥有这样的接口?)。

您肯定希望使用选项 2 来减少您的痛苦,除非它让您再次回到原点(用您不想向客户端公开的类型污染命名空间)。

为了全面披露,有两个注意事项:

1) 使用反射与直接实例化和调用有一个(小)开销。 如果您转换到接口,您只需支付实例化的反射成本。 在任何情况下,除非您在紧密循环中进行数十万次调用,否则这可能不是问题。

2) 没有什么可以阻止一个坚定的客户找出类名并做同样的事情,但如果我正确理解你的动机,你只想公开一个干净的 API,所以这真的不是一个担心。

如果我理解正确,您是在询问是否要在不公开部分来源的情况下发布您的库供 3rd 方使用? 如果是这种情况,您可以使用proguard ,它可以混淆您的库。 默认情况下,所有内容都将被排除/混淆,除非您指定要从混淆/排除中排除的内容。

如果您想分发 [部分] 代码而客户端根本无法访问它,这意味着客户端也将无法执行它。 :-O

因此,您只有一个选择:将代码的合理部分放入公共服务器并分发代理来访问它,这样您的代码将保留并在您的服务器中执行,并且客户端仍然可以通过代理,但不直接访问它。

您可以使用 servlet、Web 服务、RMI 对象或简单的 TCP 服务器,具体取决于代码的复杂程度。

这是我能想到的最安全的方法,但它也值得付出代价:除了使您的系统变得复杂之外,它还会为每个远程操作引入网络延迟,这可能会很重要,具体取决于性能要求。 此外,您应该保护服务器本身,以避免黑客入侵。 如果您已经拥有可以利用的服务器,这可能是一个很好的解决方案。

使用 Kotlin 时,您可以对库类使用internal修饰符。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM