Подтвердить что ты не робот

Как запретить клиенту просматривать внутренние частные классы в библиотеке Android?

У меня есть библиотека с несколькими пакетами -

позволяет сказать пакет a; пакет b;

внутри пакета a у меня есть public a_class
внутри пакета b У меня есть public b_class
a_class использует b_class.

Мне нужно сгенерировать библиотеку из этого, но я не хочу, чтобы клиент видел b_class.

Единственное решение, о котором я знаю, - это сгладить мои прекрасно понятные пакеты для отдельного пакета и использовать пакетный доступ по умолчанию для b_class. Есть ли другой способ сделать это? возможно, используя интерфейсы или какой-либо шаблон дизайна?

4b9b3361

Ответ 1

Мне нужно создать библиотеку из этого, но я не хочу, чтобы клиент увидел b_class. Единственное решение, о котором я знаю, - это сгладить мои красиво понятные пакеты для отдельного пакета и использовать пакетный доступ по умолчанию для b_class. Есть ли другой способ сделать это?

Да, сделайте b_class package-private (доступ по умолчанию) и создайте его с помощью отражения для использования в 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 (не очень весело, но достаточно легко и может быть нормально, если у вас есть только несколько методов с несколькими параметрами).
  • Имейте b_class реализовать интерфейс, который вы не возражаете против того, что клиент видит и передает ваш экземпляр b_class на этот интерфейс (чтение между строками, которые, как я подозреваю, у вас уже есть такой интерфейс?).

Вы обязательно захотите пойти с вариантом 2, чтобы свести к минимуму вашу боль, если он снова не вернется к квадрату (загрязняя пространство имен теми типами, которые вы не хотите подвергать клиенту).

Для полного раскрытия, две заметки:

1) Существует (небольшая) накладная часть для использования отражения против прямого инстанцирования и вызова. Если вы перейдете к интерфейсу, вы заплатите только стоимость размышлений о создании. В любом случае это, вероятно, не проблема, если вы не создадите сотни тысяч вызовов в узком цикле.

2) Нет ничего, что помешало бы определенному клиенту узнать имя класса и сделать то же самое, но если я правильно понимаю вашу мотивацию, вы просто хотите разоблачить чистый API, так что это не вызывает беспокойства.

Ответ 2

Если вы отказываетесь переместить код на отдельный контролируемый сервер, все, что вы можете сделать, это помешать программисту-клиенту при попытке использовать ваши API. Позвольте начать применять хорошие методы к вашему дизайну:

  • Пусть ваши пакеты организованы так, как они есть сейчас.
  • Для каждого класса, который вы хотите "скрыть":

    • Сделать это непубличным.
    • Извлеките свой общедоступный API в новый открытый интерфейс:

    public interface MyInterface {...}

    • Создайте общедоступный класс factory, чтобы получить объект этого типа интерфейса.

    public class MyFactory { public MyInterface createObject(); }

До сих пор у вас теперь ваши пакеты слабо связаны, а классы реализации теперь являются частными (как проповедуют хорошие практики, и вы уже сказали). Тем не менее, они еще доступны через интерфейсы и фабрики.

Итак, как вы можете избежать того, что клиенты "незнакомого" выполняют ваши частные API? Следующее - творческое, немного сложное, но действительное решение, основанное на том, чтобы помешать программистам-клиентам:

Измените классы factory: добавьте к каждому методу factory новый параметр:

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" этой реализации не будет найден, даже если клиент-программист решит декомпилировать код.

Что вы получаете от этого? В принципе, нужно отговорить программиста от использования factory, который требует неизвестного, недокументированного, непонятного объекта. Классы factory должны не беспокоиться о том, чтобы не получать нулевой объект, а также вызывать метод фиктивного метода и проверять возвращаемое значение, но оно не равно нулю (или, если вы хотите более высокий уровень безопасности, добавьте недокументированное правило секретного ключа).

Итак, это решение опирается на тонкую запутывание вашего API, чтобы препятствовать тому, чтобы клиент-программист использовал его напрямую. Чем более неясны названия интерфейса Macguffin и его методы, тем лучше.

Ответ 3

Если я правильно понимаю, вы спрашиваете о публикации своей библиотеки для стороннего использования, не раскрывая часть вашего источника? Если в этом случае вы можете использовать proguard, который может запутать вашу библиотеку. По умолчанию все будет исключено/запущено, если вы не укажете, какие объекты вы хотите исключить из обфускации/исключения.

Ответ 4

Если вы хотите распространять [часть] вашего кода, если клиент не имеет доступа к нему вообще, это означает, что клиент также не сможет его выполнить.: -O

Таким образом, у вас есть только один вариант: поместите разумную часть вашего кода в общедоступный сервер и распространите прокси для доступа к нему, чтобы ваш код был сохранен и выполнен на вашем сервере, и клиент все равно сможет выполнить его через прокси, но без прямого доступа к нему.

В зависимости от уровня сложности вашего кода вы можете использовать сервлет, веб-сервис, объект RMI или простой TCP-сервер.

Это самый безопасный подход, который я могу придумать, но он также заслуживает цены: в дополнение к комплексообразованию вашей системы он будет вводить сетевую задержку для каждой удаленной операции, что может быть большой проблемой в зависимости от требований к производительности, Кроме того, вы должны обеспечить защиту самого сервера, чтобы избежать хакерских вторжений. Это может быть хорошим решением, если у вас уже есть сервер, на котором вы могли бы воспользоваться.