Thursday, January 5, 2017

Get personal app code and display it

Leave a Comment

I am trying to get the app code and display it, for an example if button X starts a new activity then a textView displays the whole method

I reached only how can I display code in HTML format from this question

But is there is a way to get the code of my app out, I think that there are 2 ways

  1. An Internal one by getting it by the app itself
  2. An External one by reading the java file then filtering it and getting the text of the method

Is there are any ideas about that?

Thanks in advance

2 Answers

Answers 1

Let's start with a broader overview of the problem:

  1. Display App code

  2. Press X button

  3. Open new activity with a textview which displays the method

The goal is to do the following:

  1. Viewing app method by extracting it and then building & running it.

There are some methods we can use to run Java/Android code dynamically. The way I would personally do it is DexClassLoader and with Reflection.

If you need more details, let me know. Here is what it'd do though:

  1. View app method
  2. Upon pressing X, launch intent with extra to new Activity
  3. Parse and compile code dynamically and then run it with DexClassLoader and Reflection

Sources:

Sample file loading Java method from TerminalIDE Android App

Android Library I made for Auto-Updating Android Applications without needing the Play Store on non-root devices

Answers 2

The above is not currently possible as mentioned by others is the comments. What i can suggest is shipping your application with the source code in the assets folder and using a helper function to extract a certain methods from the source at runtime (your second proposed approach). I have written example code but it is in pure java and needs to be ported to android (a few lines).

NB: You may need to reformat the code after extraction depending on your use case.

Hope it helps :)

The code for the helper method:

static String getTheCode(String classname ,String methodSignature ) throws FileNotFoundException {       //**********************A few lines of code below need changing when porting ***********//      // open file, your will be in the assets folder not in the home dir of user, don't forget the .java extension when porting      File file = new File(System.getProperty("user.home") +"/"+ classname +".java");      // get the source, you can use FileInputReader or some reader supported by android      Scanner scanner = new Scanner(file);      String source = "";     while(scanner.hasNext()) {        source += " "+ scanner.next();     }       //**********************The above code needs changing when porting **********//      // extract code using the method signature      methodSignature = methodSignature.trim();     source = source.trim();      //appending { to differentiate from argument as it can be matched also if in the same file     methodSignature = methodSignature+"{";      //making sure we find what we are looking for     methodSignature = methodSignature.replaceAll("\\s*[(]\\s*", "(");     methodSignature = methodSignature.replaceAll("\\s*[)]\\s*", ")");     methodSignature = methodSignature.replaceAll("\\s*[,]\\s*", ",");     methodSignature = methodSignature.replaceAll("\\s+", " ");       source =source.replaceAll("\\s*[(]\\s*", "(");     source = source.replaceAll("\\s*[)]\\s*", ")");     source = source.replaceAll("\\s*[,]\\s*", ",");     source = source.replaceAll("\\s+", " ");       if(!source.contains(methodSignature)) return null;      // trimming all text b4 method signature     source = source.substring(source.indexOf(methodSignature));      //getting last index, a methods ends when there are matching pairs of these {}     int lastIndex = 0;      int rightBraceCount = 0;     int leftBraceCount = 0;      char [] remainingSource = source.toCharArray();     for (int i = 0; i < remainingSource.length ; i++          ) {          if(remainingSource[i] == '}'){              rightBraceCount++;              if(rightBraceCount == leftBraceCount){                  lastIndex = (i + 1);                 break;             }          }else if(remainingSource[i] == '{'){              leftBraceCount++;         }         }       return  source.substring(0 ,lastIndex);  } 

Example usage (getTheCode methods is static and in a class called GetTheCode):

public static void main(String... s) throws FileNotFoundException {        System.out.println(GetTheCode.getTheCode("Main", "private static void shoutOut()"));     System.out.println(GetTheCode.getTheCode("Main", "private static void shoutOut(String word)"));   } 

Output:

private static void shoutOut(){ // nothing to here } private static void shoutOut(String word){ // nothing to here } 

NB: When starting your new activity create a method eg

 private void myStartActivty(){   Intent intent = new Intent(MyActivity.this, AnotherActivity.class);      startActivity(intent);  } 

Then in your onClick:

@Override public void onClick(View v) {     myStartActivity();      myTextView.setText(GetTheCode.getTheCode("MyActivity","private void myStartActivity()")); } 

Update: Ported the Code for android:

    import android.content.Context;      import java.io.IOException;     import java.util.Scanner;      public class GetTheCode {   static String getTheCode(Context context, String classname , String methodSignature ) {     Scanner scanner = null;     String source = "";     try {         scanner = new Scanner(context.getAssets().open(classname+".java"));        while(scanner.hasNext()) {        source += " "+ scanner.next();     }      } catch (IOException e) {         e.printStackTrace();         return null;     }         scanner.close();      // extract code using the method signature      methodSignature = methodSignature.trim();     source = source.trim();      //appending { to differentiate from argument as it can be matched also if in the same file     methodSignature = methodSignature+"{";      //making sure we find what we are looking for     methodSignature = methodSignature.replaceAll("\\s*[(]\\s*", "(");     methodSignature = methodSignature.replaceAll("\\s*[)]\\s*", ")");     methodSignature = methodSignature.replaceAll("\\s*[,]\\s*", ",");     methodSignature = methodSignature.replaceAll("\\s+", " ");       source =source.replaceAll("\\s*[(]\\s*", "(");     source = source.replaceAll("\\s*[)]\\s*", ")");     source = source.replaceAll("\\s*[,]\\s*", ",");     source = source.replaceAll("\\s+", " ");       if(!source.contains(methodSignature)) return null;      // trimming all text b4 method signature     source = source.substring(source.indexOf(methodSignature));      //getting last index, a methods ends when there are matching pairs of these {}     int lastIndex = 0;      int rightBraceCount = 0;     int leftBraceCount = 0;      char [] remainingSource = source.toCharArray();     for (int i = 0; i < remainingSource.length ; i++          ) {          if(remainingSource[i] == '}'){              rightBraceCount++;              if(rightBraceCount == leftBraceCount){                  lastIndex = (i + 1);                 break;             }          }else if(remainingSource[i] == '{'){              leftBraceCount++;         }         }       return  source.substring(0,lastIndex);     }  } 

Usage:

   // the method now takes in context as the first parameter, the line below was in an Activity   Log.d("tag",GetTheCode.getTheCode(this,"MapsActivity","protected void onCreate(Bundle savedInstanceState)")); 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment