Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

app.exec() - run system shell command #15

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

PawelSuwinski
Copy link

@PawelSuwinski PawelSuwinski commented Dec 10, 2020

Ability to execute system commands and shell scripts from androidjs app. There are quite a lot of handy utilities in android system like am, toybox, sh, setprop, getprop, logcat which can be use for backend processing leaving nodejs for more advanced tasks. Linux/ shell powerusers can accomplish quite a bit of using these.

Examples of usage:

// start intent using ActivitiManager
const file = 'file://' + app.getPath('downloads') + '/doc.pdf';
app.exec('am', [...'start --user 0 -a android.intent.action.VIEW -d'.split(' '), file]);

// get some prop setting
const model = app.exec('getprop', 'ro.vendor.product.model').stdout || 'unknown';

// load file
const fileContent = app.exec('toybox', ['cat', fileName]).stdout || null;

To chain commands, to use output redirections and other advanced stuff use shell:

// count logged expression 
console.log('counter: ' + app.exec('sh', ['-c', 'logcat -d | toybox grep denied | toybox wc -l']).stdout);

// save data to file
app.exec('sh', ['-c', `echo '${myData}' > '${fileName}'`]);

Commands are executed in blocking synchronous manner so to process some longer lasting tasks use shell background processing. To check if background task completed and to get results setInterval() method could be used:

const file = 'out.txt';
app.exec('sh', ['-c', `(sleep 10 && date > ${file}) &`]);

const checker = setInterval(() => {
  const res = app.exec('sh', ['-c', `test -s '${file}' && while read -r l; do echo $l; done < '${file}'`]);
  res.stdout && onCompleteCallback(res.stdout) && clearInterval(checker);
}, 1000);

It could be also accomplished in more reactive manner realizing http server using shell and netcat (toybox nc) on backend side and regular xhr requests on frontend side. For an example and as a starting point see: https://github.com/AdamDanischewski/bashttpd

Some notes on it:

  • bash only syntax need to be rewritten for mksh compatibility and any external command changed to toybox equivalents
  • for secuirity listen to localhost only and use session token, without tokens it is wide open for any local app/user
  • add CORS extra response header ''Access-Control-Allow-Origin: *" to use with xhr in androidjs context

Here is a demo app to test app.exec() API: myapp-202012101200.zip

For more see also:

[Related android-js/androidjs#60, Fix android-js/androidjs#153] i

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

open a file or url in an external app, trigger android.intent.action.VIEW|SEND
1 participant