0

I want to change the value of variable in xml. The value is based on another file which read by editXml.sh. So I need to run the editXml.sh before app is compiled.

I try to run the script in MainActivity with code as follows:

onCreate() {
......
execScript();
}

execScript(){
    try{
        Runtime rt = Runtime.getRuntime();
        Process proc = rt.exec("sh /.../editXml.sh");
    } catch(Throwable t)
    {
        t.printStackTrace();
    }

}

The editXml.sh is in my local, but the code doesn't work when I run app in Android studio.(Works on local) Should I put my script in the app? And which part of the app? Any suggestion?

ellen zhu
  • 67
  • 3
  • 8

3 Answers3

1

Try this. I've tested this code and it works. Let's you script named script.sh.

  1. Put file script.sh to you project's /res/raw folder.
  2. Use code below.
  3. Build apk. Unpack apk (this is usual zip-archive) and make sure file /res/raw/script.sh exists there.
  4. Install apk on device and start it.

        public static void executeCommandAndGetOutput(String command){
            BufferedReader reader = null;
            String result = "";
            try {
                Process p = Runtime.getRuntime().exec(command);
                reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
                String line = null;
                while ((line = reader.readLine()) != null){
                    result += line + "\n";
                }
                p.waitFor();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if(reader != null)
                    try {
                        reader.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
            }
            Log.i("Test", result);
        } 
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            String pathToScript = getDir("my_scripts", 0).getAbsolutePath() + File.separator + "script.sh";
    
            // Unpacking script to local filesystem
            InputStream in = getResources().openRawResource(R.raw.script);
            FileOutputStream out = null;
            try {
                out = new FileOutputStream(pathToScript);
                byte[] buff = new byte[1024];
                int read = 0;
                while ((read = in.read(buff)) > 0) {
                out.write(buff, 0, read);
                }
            }
            catch(Exception e){
            }
            finally {
                try {
                    in.close();
                    out.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
            // Make script executable
            executeCommand("chmod 775 " + pathToScript);
            // Execute script
            executeCommand("sh " + pathToScript);
        }
    
    public static String getSystemCommandOutput(String command){
        BufferedReader reader = null;
        String result = "";
    
        try {
            Process p = Runtime.getRuntime().exec(command);
            reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
    
            String line = null;
            while ((line = reader.readLine()) != null){
                result += line + "\n";
            }
    
            p.waitFor();
    
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeQuietly(reader);
        }
    
        return result;    
    } 
    
Fox
  • 417
  • 4
  • 13
  • hey, I used your code and I can get the unpack path: /data/data/cc.softwarefactory.lokki.android/app_my_scripts/editxml.sh. But why the result is null. It should be the contents of script file, right? The output of console picture is in the next answer. – ellen zhu Aug 06 '15 at 10:04
  • bty, I need to execute the script to change data value before the code settled finally. But after unpacking from "apk", the script execute and change the value. It means the code is recompiled? – ellen zhu Aug 06 '15 at 10:25
  • Did you mean you need to change value before build apk? Which value? At /res/values? – Fox Aug 06 '15 at 11:09
  • I need to read value from /res/values like this: String value = getResources().getString(R.string.LogoutButton) in mainActivity. And the value is changed by script file. – ellen zhu Aug 06 '15 at 11:18
  • The value is changed by script before reading. So the script need to be executed first. – ellen zhu Aug 06 '15 at 11:30
  • Hmmm. Why you want to change value at resources? It constant and cannot be changed. Can you get value directly from script output? String value = getSystemCommandOutput("sh " + pathToScript). See example of getSystemCommandOutput() at this answer. Your script need to write value at output (echo my_value) – Fox Aug 06 '15 at 11:56
  • Well, since there will be more than one value I want to changed through script, if I get value from script output, I need execute many scripts. But I think your approach is avaible, too. But can't I change value at resources? – ellen zhu Aug 06 '15 at 12:07
  • Resource values is constant. See http://stackoverflow.com/questions/8258650/is-it-possible-to-change-value-of-string-added-in-res-strings-xml-in-android-at and http://stackoverflow.com/questions/9674925/change-value-of-r-string-programically – Fox Aug 06 '15 at 12:12
  • Maybe you don't need sh-script? Can you realize algorithm of calculating values on java? – Fox Aug 06 '15 at 12:13
  • Here is the situation: There is a configure file(can't be changed and not include in app file) guiding the value. I need script to read the value from configure file then apply to activity. Any idea can implement this except script? – ellen zhu Aug 06 '15 at 12:29
  • And why I still get nothing from String value = getSystemCommandOutput("sh " + pathToScript). Console still shows value: not found. – ellen zhu Aug 06 '15 at 12:36
  • Will values change at run-time of android application? Or you need to change values before build apk and this values will be constants in application? – Fox Aug 06 '15 at 12:39
  • Seems to be android haven't "sh" program by default. It can be used on rooted devices with busybox installed: http://android.stackexchange.com/questions/53634/adb-shell-sbin-sh-command-not-found – Fox Aug 06 '15 at 12:48
  • I need to change values before build apk then them will be constants. So should I use script? – ellen zhu Aug 06 '15 at 12:54
  • You can run script during build. But you DON'T need to run it FROM ANDROID APPLICATION. Run it from gradle script before build resources. – Fox Aug 06 '15 at 12:56
  • But can I change the value in activity when run script from gradle? Because the app was compiled before building, which means it will be rebuilded? – ellen zhu Aug 06 '15 at 13:01
  • You can change values at /res/values/string.xml before building resources and then get values from activity with getResources().getString(...). What do you mean "app was compiled before building"? – Fox Aug 06 '15 at 13:07
  • I am new programmer. I thought the app would be compiled before builded technically.... – ellen zhu Aug 06 '15 at 13:13
  • Now I have got your solution. I will change value from string.xml and run script from gradle. Thanks very much. – ellen zhu Aug 06 '15 at 13:18
0

You can put script at raw resources and then unpack it to Context.getDir(...) folder and run from there with absolute path.

Also you need to run "chmod 775" (chmod +x) for this file before executing.

Example about copying a file from raw: Copying raw file into SDCard? You can copy to app folder (Context.getDir(...)) instead of sdcard

Community
  • 1
  • 1
Fox
  • 417
  • 4
  • 13
  • thanks for your answer. Let's say I run the script through this way: File script = Context.getDir("editXml", 0); Process proc = rt.exec("sh script"); the script can't be recognized in exec(). How to solve this? – ellen zhu Aug 05 '15 at 10:45
  • Try: exec("sh " + Context.getDir("editXml", 0) + "\script.sh"). If error occured - do chmod (see answer) – Fox Aug 05 '15 at 10:58
  • getDir() returns FOLDER. You need to put script there and run it with FULL PATH. – Fox Aug 05 '15 at 11:00
  • Thanks for your patient answers. I add "chmod +x", and it works! – ellen zhu Aug 05 '15 at 12:31
  • It works when run script from studio terminal, but doesn't work when run through code: Process proc2 = rt.exec("sh " + this.getDir("raw",0) + "/editxml.sh"). I put editxml.sh into raw folder. What's the problem it maybe? It didn't say any error message when debug. – ellen zhu Aug 05 '15 at 13:21
  • Have you copied script from raw-resource to folder Context.getDir("editXml", 0)? See answer about copying file from raw to folder – Fox Aug 05 '15 at 13:57
  • I didn't get what your mean, sorry. editxml.sh is the script file which I put into folder raw. And I get script file path from "this.getDir("raw",0) + "/editxml.sh"". Then I use command "sh" to run it. Am I wrong? – ellen zhu Aug 05 '15 at 14:08
  • Your script will be in apk-file raw folder. You can't run it directly. You need to unpack it to any app's data dir (Context.getDir("editXml", 0), for example) and run it from there. How to unpack - see link from answer – Fox Aug 05 '15 at 14:13
  • Well, I understand the process finally. But the unpacking failed. I created a file "script" in folder values, and use FileOutputStream out = new FileOutputStream(this.getDir("res/values/script", 0)) to unpack. To execute the file by using " Process proc = rt.exec("sh " + this.getDir("res/values",0) + "/script.sh");"The error is "Error:Premature end of file", and I also tried file name "script.sh". The same error happened. Could you help me? Many thanks. – ellen zhu Aug 06 '15 at 07:47
  • Well, see next answer with complete code example. And accept it, if it's clear – Fox Aug 06 '15 at 09:00
0

console output:

     58:07.979    8935-8935/cc.softwarefactory.lokki.android   E/MainActivity﹕ onCreate
     12:58:08.234    8935-8935/cc.softwarefactory.lokki.android E/MainActivity﹕ PATH: /data/data/cc.softwarefactory.lokki.android/app_my_scripts/editxml.sh
     12:58:08.258    8935-8935/cc.softwarefactory.lokki.android E/MainActivity﹕ result:
     12:58:08.287    8935-8935/cc.softwarefactory.lokki.android E/MainActivity﹕ result: not found

I changed

 Log.i("Test", result) to Log.e(TAG,"result: " + result);
ellen zhu
  • 67
  • 3
  • 8