¿Cómo evitar que el cliente vea clases privadas internas en la biblioteca de Android?

Tengo una biblioteca con varios paquetes-

digamos
Paquete a;
Paquete b;

Dentro del paquete a Tengo público a_class
Dentro del paquete b Tengo público b_class
A_class utiliza b_class.

Necesito generar una biblioteca de esto, pero no quiero que el cliente vea b_class.

La única solución que conozco es aplastar mis paquetes maravillosamente comprensibles a un paquete único y usar el acceso por paquetes predeterminado para b_class. ¿Hay otra manera de hacerlo? Tal vez utilizando interfaces o alguna forma de patrón de diseño ??

4 Solutions collect form web for “¿Cómo evitar que el cliente vea clases privadas internas en la biblioteca de Android?”

Necesito generar una biblioteca de esto, pero no quiero que el cliente vea b_class. La única solución que conozco es aplastar mis paquetes maravillosamente comprensibles a un paquete único y usar el acceso por paquetes predeterminado para b_class. ¿Hay otra manera de hacerlo?

Sí, haga b_class package-private (acceso por defecto) e instáncielo vía reflexión para usarlo en a_class .

Dado que conoce el nombre completo de la clase, carga reflexivamente la clase:

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

Busque el constructor que desea invocar:

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

Permítase invocar al constructor haciéndolo accesible:

 con.setAccessible(true); 

Invoque al constructor para obtener su instancia b_class :

 Object o = con.newInstance(); 

Hurray, ahora tienes una instancia de b_class . Sin embargo, no puede llamar a los métodos de b_class en una instancia de Object , por lo que tiene dos opciones:

  1. Utilice la reflexión para invocar los métodos de b_class (no es muy divertido, pero es bastante fácil y puede estar bien si sólo tiene unos pocos métodos con pocos parámetros).
  2. ¿ b_class implementar una interfaz que no le importa que el cliente vea y emitir su instancia de b_class a esa interfaz (lectura entre las líneas que sospecho que ya puede tener una interfaz de este tipo?).

Definitivamente querrá ir con la opción 2 para minimizar su dolor a menos que se vuelve a cuadrar uno de nuevo (contaminación del espacio de nombres con tipos que no desea exponer al cliente).

Para la divulgación completa, dos notas:

1) Hay una (pequeña) sobrecarga para el uso de reflexión vs instanciación directa y la invocación. Si edita una interfaz, sólo pagará el costo de la reflexión sobre la instancia. En cualquier caso, probablemente no sea un problema a menos que hagas cientos de miles de invocaciones en un bucle cerrado.

2) No hay nada para detener a un cliente determinado de averiguar el nombre de la clase y hacer lo mismo, pero si entiendo su motivación correctamente sólo desea exponer una API limpia, por lo que esto no es realmente una preocupación.

Si rechaza mover el código a un servidor individual controlado, todo lo que puede hacer es obstaculizar al programador cliente cuando intenta utilizar sus API. Comencemos a aplicar buenas prácticas a su diseño:

  1. Deje sus paquetes organizados como están ahora.
  2. Para cada clase que quieras "ocultar":

    • Que no sea público.
    • Extraiga su API pública a una nueva interfaz pública:

    public interface MyInterface {...}

    • Cree una clase de fábrica pública para obtener un objeto de ese tipo de interfaz.

    public class MyFactory { public MyInterface createObject(); }

Hasta ahora, ahora tienes tus paquetes ligeramente acoplados, y las clases de implementación son ahora privadas (como buenas prácticas predican, y ya dijiste). Sin embargo, todavía están disponibles a través de las interfaces y fábricas.

Entonces, ¿cómo puede evitar que los clientes "extraños" ejecuten sus APIs privadas? Lo que viene a continuación es una solución creativa, un poco complicada, pero válida, basada en obstaculizar a los programadores clientes:

Modifique sus clases de fábrica: Agregue a cada método de fábrica un nuevo parámetro:

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

Entonces, ¿qué es Macguffin ? Es una nueva interfaz que debe definir en su aplicación, con al menos un método:

 public interface Macguffin { public String dummyMethod(); } 

Pero no proporcionan ninguna implementación utilizable de esta interfaz. En todos los lugares de tu código necesitas proporcionar un objeto Macguffin , crearlo a través de una clase anónima :

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

O aún más avanzado, a través de un objeto proxy dinámico , por lo que no se encontrará ningún archivo ".class" de esta implementación aunque el programador cliente se atreva a descompilar el código.

¿Qué obtienes de esto? Básicamente es disuadir al programador de usar una fábrica que requiere un objeto desconocido, indocumentado e incomprensible. Las clases de fábrica deberían preocuparse por no recibir un objeto nulo, y para invocar el método ficticio y comprobar el valor de retorno, tampoco es nulo (o, si desea un nivel de seguridad más alto, agregue una regla de clave secreta indocumentada).

Así que esta solución se basa en una sutil ofuscación de su API, para desalentar al programador cliente a utilizarlo directamente. Cuanto más oscurezca los nombres de la interfaz Macguffin y sus métodos, mejor.

Si entiendo correctamente usted está preguntando sobre la publicación de su biblioteca para el uso de terceros sin revelar parte de su fuente? Si ese es el caso, puede usar proguard , lo que puede ofuscar su biblioteca. De forma predeterminada, todo quedará excluido / ocultado, a menos que especifique las cosas que desea excluir de la ofuscación / exclusión.

Si desea distribuir [parte de] su código sin que el cliente pueda acceder a él en absoluto, eso significa que el cliente no podrá ejecutarlo tampoco. O

Por lo tanto, sólo tiene una opción: Ponga la parte sensible de su código en un servidor público y distribuir un proxy para acceder a él, de modo que su código se mantendrá y ejecutado en su servidor y el cliente todavía podría ejecutar a través de El proxy pero sin acceder directamente.

Puede utilizar un servlet, un servicio web, un objeto RMI o un servidor TCP simple, dependiendo del nivel de complejidad de su código.

Este es el enfoque más seguro que puedo imaginar, pero también merece un precio a pagar: Además de complicar su sistema, se introduciría un retraso de la red para cada operación remota, lo que podría ser gran cosa dependiendo de los requisitos de rendimiento. Además, debe garantizar el servidor en sí, para evitar intrusiones hacker. Esto podría ser una buena solución si ya tiene un servidor que podría aprovechar.

  • Compruebe si existe un archivo
  • Valor de preferencia personalizada de Android no guardado
  • Render un byte como mapa de bits en Android
  • Cómo utilizar los servicios de juegos de Google Play con LibGdx
  • ImageView.getWidth () devuelve 0
  • No se puede obtener android.support.v7.widget.SearchView para aceptar el texto
  • Obtener bandera emoji por código de país
  • Android, encuentra todos los lugares en código para solicitar permisos
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.