Sou novo no java, e estou com esta dúvida, na qual já pesquisei de tudo, já tentei de tudo, e nada.
Eu tenho um arquivo java (teste.java) na raiz do sdcard. Dentro deste java tenho uma classe tambem como nome teste, resumidamente assim:
…
import …
…
public class teste {
…
}
Como é que eu faço para usar esta classe? Ou seja, chamar uma classe fora da aplicacao? dinamicamente?
Eu fiz:
try {
URLClassLoader ucl = URLClassLoader.newInstance( new URL[] { getClass().getResource(Environment.getExternalStorageDirectory().toString() +
"/teste.java") }
);
Class<?> classe = ucl.loadClass(“teste”); // Já aqui dá erro: A URL is null
Object instancia = classe.newInstance();
Method metodo = classe.getMethod(“calcular”, double.class ); // Este calcular está dentro da classe teste: public double calcular(double x) { …
resultado = (Double) metodo.invoke(instancia, x);
} catch (Exception exc) {
exc.printStackTrace();
}
Eu acho que é por aí… Eu uso Froyo, eclipse e java 1.8. Diante mão já agradeço qualquer ajuda.
Bom, acho que tem muito coisa errada ai, mas vamos por partes:
Vc não usa .java em tempo de execução, os arquivos precisam estar compilados (.class)
Não conheço uma forma não gambiarresca de importar dinamicamente um class qualquer, eles precisar estar no classpath da aplicação quando ela iniciar.
Rodrigo, nao tem algum modo de fazer isso nao? Ao invez de um arquivo java no sdcard um jar no sdcard, e pegar a classe dentro dele? Ou algum outro: um txt, um html, etc?
O que eu realmente quero é o seguinte:
Tenho um aplicativo no celular. Mas o aplicativo para funcionar precisa (ao iniciar) ir na internet e baixar um arquivo (teste.java) e gravar no sdcard. Dai com este arquivo no sdcard, é que o aplicativo vai usar ele e depois é que vai ser executado. O que eu quero com isso? Dificultar uma engenharia reversa…
Diante mao já agradeço a ajuda…
Para carregar um .class
dinamicamente, você precisa especializar um ClassLoader
e usar o método defineClass
para transformar um array de bytes em um objeto Class
.
Após isso consegue manipular o objeto Class
através de reflection.
Mas não é algo trivial de implementar.
Se você tem medo de engenharia reversa, recomendo que ofusque seu bytecode, há vários ofuscadores, o ProGuard, por exemplo, é bem famoso.
Como falei, até dá, carregar um jar ou .class., mas é bem gambiarresco assim como o staroski falou, não é trivial e tem solução melhor pra isso. A sua ideia tbm permite carregar código malicioso pro seu app, se alguem descobrir pode facilmente injetar um exploit nele.
Rodrigo e starosk, nesse caso, como é dificil de implementar, e nao tem a seguranca que eu desejo (… um exploit nele), vou procurar outra maneira. O proguard eu já uso, mas toda vez que descompilo vejo tudo lá. O que eu queria era dificultar mais ainda que o proguard oferece… No clipper e no delphi o executavel nem abre quando se tenta descomplilar. Que dizer, no delphi chega ate a descompilar, mas fica tudo em assembler. O que se chega a ver é algumas telas…Obrigado aos dois…
Então não estás configurando ele adequadamente.
Tenta configurar ele para zoar os nomes de métodos e classes.
E melhor ainda, tenta recompilar um código descompilado.
É, eu acho que nao tou usando bem o proguard. Vou estudar para fazer: “zoar os nomes de métodos e classes”. E sobre: “tenta recompilar um código descompilado”, realmente, eu já tentei recompilar novamente meu proprio codigo ofuscado e nao consegui de jeito nenhum. Mas aproveitando o ensejo, pesquisei bem antes deste topico, e achei duas interessantes:
import java.io.;
import java.util.;
import java.lang.reflect.*;
public class MakeTodayClass {
Date today = new Date();
String todayMillis = Long.toString(today.getTime());
String todayClass = “z_” + todayMillis;
String todaySource = todayClass + “.java”;
public static void main (String args[]){
MakeTodayClass mtc = new MakeTodayClass();
mtc.createIt();
if (mtc.compileIt()) {
System.out.println(“Executando " + mtc.todayClass + “:\n\n”);
mtc.runIt();
}
else
System.out.println(mtc.todaySource + " é ruim.”);
}
public void createIt() {
try {
FileWriter aWriter = new FileWriter(todaySource, true);
aWriter.write(“public class “+ todayClass + “{”);
aWriter.write(” public void doit() {”);
aWriter.write(" System.out.println(""+todayMillis+"");");
aWriter.write(" }}\n");
aWriter.flush();
aWriter.close();
}
catch(Exception e){
e.printStackTrace();
}
}
public boolean compileIt() {
String [] source = { new String(todaySource)};
ByteArrayOutputStream baos= new ByteArrayOutputStream();
new sun.tools.javac.Main(baos,source[0]).compile(source);
// se você usa JDK >= 1.3 então use
// public static int com.sun.tools.javac.Main.compile(source);
return (baos.toString().indexOf("erro")==-1);
}
public void runIt() {
try {
Class params[] = {};
Object paramsObj[] = {};
Class thisClass = Class.forName(todayClass);
Object iClass = thisClass.newInstance();
Method thisMethod = thisClass.getDeclaredMethod(“doit”, params);
thisMethod.invoke(iClass, paramsObj);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
Nesta nao consigo o: new sun.tools.javac.Main(baos,source[0]).compile(source);
Este abaixo é daqui mesmo: Criando classes em tempo de execução
/**
- Classe que define os métodos de compilação e
- execução do código que será gerado e compilado.
-
@author David Buzatto
/
import com.sun.tools.javac.;
import java.io.;
import java.lang.reflect.;
import java.net.;
import javax.swing.;
public class Engine {
public Engine() {
// inicializa o contador de classes
contadorClasses = 0;
}
// método que realiza a compilação do código inserido
public boolean compilar( String codigo ) {
// criando código da classe
String codClasse =
"/**\n"
+ " * Classe gerada dinamicamente.\n"
+ " \n"
+ " * @author David Buzatto\n"
+ " /\n\n\n"
+ "import static java.lang.Math.;\n\n"
+ "import java.math.;\n\n\n"
+ “public class Expressao” + contadorClasses + " {\n\n"
+ " public double calcular( double x ) {\n\n"
+ " return " + codigo + “;\n\n”
+ " }\n\n"
+ “}”;
try {
// deixa um log da compilacao num arquivo chamado logCompilacao.txt
PrintWriter saida = new PrintWriter(
new FileWriter( “logCompilacao.txt” ) );
// grava o codigo-fonte no disco
String arquivoFonte = “Expressao”
+ contadorClasses + “.java”;
FileWriter writer = new FileWriter( arquivoFonte );
//grava no arquivo o código
writer.write( codClasse );
writer.close();
// compila o código gerado,
// saida é onde será gravada a saída do compilador
int resultadoCompilacao = Main.compile(
new String[] { arquivoFonte }, saida );
if ( resultadoCompilacao == 0 ) {
return true;
} else {
// lê o arquivo de resultados e imprime na tela
BufferedReader resultado = new BufferedReader(
new FileReader( “logCompilacao.txt” ) );
String linha;
while( ( linha = resultado.readLine() ) != null ) {
System.out.println( linha + “\n” );
}
saida.close();
return false;
}
} catch( IOException exc ) {
System.out.println( “Erros ao gravar arquivo: \n” + exc.getMessage());
exc.printStackTrace();
return false;
}
}
// executa a classe, selecionando o método de cálculo
public double executar( double x ) {
double resultado = 0;
try {
URLClassLoader ucl = URLClassLoader.newInstance(
new URL[] {
getClass().getResource( “Empressao” + contadorClasses ) }
);
Class classe = ucl.loadClass( “Empressao” + contadorClasses );
// cria instância da classe
Object instancia = classe.newInstance();
// obtém o método desejado
Method metodoCalcular = classe.getMethod(
“calcular”, double.class );
// invoca o método, passando como parâmetro
// uma instância da classe que ele pertence
resultado = ( Double ) metodoCalcular.invoke(
instancia, x );
/// referência a classe
Class classe = Class.forName( “Expressao”
+ contadorClasses );
// cria instância da classe
Object instancia = classe.newInstance();
// obtém o método desejado
Method metodoCalcular = classe.getMethod(
“calcular”, double.class );
// invoca o método, passando como parâmetro
// uma instância da classe que ele pertence
resultado = ( Double ) metodoCalcular.invoke(
instancia, x );/
} catch ( Exception exc ) {
exc.printStackTrace();
}
// incrementa o contador de classes
contadorClasses++;
return resultado;
}
// conta quantas classes foram compiladas e carregadas
private int contadorClasses;
}
Tabem nao consigo rodar… Veja que nos dois casos há uma gravacao no sdcard.
Abraços…