androidのjava(processing)からnode.jsを動かす

#はじめに
皆様はandroidでjava以外を動かした事がありますか？
動かすだけならtermuxや言語ごとのアプリを使えば出来ることが多いですがapkに詰めて配布するのは難しいです(pythonについては挫折しました)
しかしながら今回紹介するNode.jsの様に先人の知恵によりandroidで動かす為の道がある程度敷かれているものもあります
ということで前置きはここまでにして実際にやり方を見ていきましょう
#必要なもの
[node in android](https://github.com/kelp404/node-in-android/releases)
androidでjavaを動かす環境
#準備
assetsに必要なものを入れていきましょう
とりあえずnpmは要らないので
assets/resource/binにダウンロードしたnodeというファイルを入れてください
WriteExternalStorageのpermissionまたはreadExternalStorageのpermissionを適宜追加してください
#import
最初に

```java
import java.io.IOException;
import java.util.Map;
import fi.iki.elonen.*;
import android.content.res.AssetManager;
import android.os.Bundle;
import java.io.*;
import java.util.*;
```

をimportしておいてください
#assetsからlocalStorageへのコピーする関数
localStorageにあるファイルしか実行できないのでcopyFiles関数でassetsから移します

```java
private boolean isDirectory(final String path) throws IOException { 
  AssetManager assetManager = getActivity().getResources().getAssets();
  boolean isDirectory = false;
  try {
    if (assetManager.list(path).length > 0) {
      isDirectory = true;
    } else {
      assetManager.open(path);
    }
  }
  catch (FileNotFoundException fnfe) {
    isDirectory = true;
  }
  return isDirectory;
}
private void copyFiles(final String parentPath, final String filename, final File toDir) throws IOException {
  AssetManager assetManager = getActivity().getResources().getAssets();
  String assetpath = (parentPath != null ? parentPath + File.separator + filename : filename);
  if (isDirectory(assetpath)) {
    if (!toDir.exists()) {
      toDir.mkdirs();
    } 
    for (String child : assetManager.list(assetpath)) {
      copyFiles(assetpath, child, new File(toDir, child));
    }
  } else {
    copyData(assetManager.open(assetpath), new FileOutputStream(new File(toDir.getParentFile(), filename)));
  }
}
private void copyData(InputStream input, FileOutputStream output) throws IOException {
  int DEFAULT_BUFFER_SIZE = 1024 * 4; 	
  byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; 	
  int n = 0; 		
  while (-1 != (n = input.read(buffer))) { 
    output.write(buffer, 0, n);
  } 		
  output.close(); 		
  input.close();
}
```

getContext(),getActivity()の部分は適当なものに変えてください
#node.jsを呼び出す関数
adbCommandExe関数でnode.jsを呼びます
sketchPath関数はlocalstorageの位置を返します
addEnv関数は環境変数を追加します

```java
String sketchPath(String path){
  return getContext().getFilesDir().getAbsolutePath()+"/"+path;
}
void addEnv(ProcessBuilder pb,String e,String value){
  Map<String, String> env = pb.environment();
  env.put(e,value);
}
private String adbCommandExe(String command,File dir) {
  StringBuilder suilder = new StringBuilder();
  ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
  if(dir!=null)processBuilder.directory(dir);
  addEnv(processBuilder,"LD_LIBRARY_PATH",sketchPath("lib"));
  addEnv(processBuilder,"PATH",sketchPath("bin"));
  addEnv(processBuilder,"LANG","en_US.UTF-8");
  InputStream iStream = null;
  InputStreamReader isReader = null;
  try {
    Process proc = processBuilder.start();
    iStream = proc.getInputStream();
    isReader = new InputStreamReader(iStream);
    BufferedReader bufferedReader = new BufferedReader(isReader);
    String line;
    while ((line = bufferedReader.readLine()) != null) {
      suilder.append(line);
      suilder.append("\n");
      println(line);
    }
    BufferedReader br = new BufferedReader(new InputStreamReader(proc.getErrorStream())); 
    while ((line = br.readLine()) != null) { 
      suilder.append(line);
      suilder.append("\n");
      println(line);
    }
  }
  catch(Exception e) {
    e.printStackTrace();
  } 
  finally {
    try {
      if (iStream != null) {
        iStream.close();
      }
      if (isReader != null) {
        isReader.close();
      }
    } 
    catch(Exception e) {
      e.printStackTrace();
    }
  }
  return suilder.toString();
}
```
#実行
関数を実際に呼び出します

```java
void run(){
  try {
    copyFiles(null, "resource", new File(sketchPath("")));
  } 
  catch (IOException ioe) { 
    println("copy error");
  }
  for(File file:new File(sketchPath("bin")).listFiles()){
    if (file.setExecutable(true, true))println("a");
  }
  for(File file:new File(sketchPath("lib")).listFiles()){
    if (file.setExecutable(true, true))println("a");
  }
  File dir = new File("/storage/emulated/0/webIDE/temp");
  adbCommandExe("node -v",dir);
}
```

#全部まとめると
node.jsを実行したい時にrun関数を呼んでみてください

```java
void run(){
  try {
    copyFiles(null, "resource", new File(sketchPath("")));
  } 
  catch (IOException ioe) { 
    println("copy error");
  }
  for(File file:new File(sketchPath("bin")).listFiles()){
    if (file.setExecutable(true, true))println("a");
  }
  for(File file:new File(sketchPath("lib")).listFiles()){
    if (file.setExecutable(true, true))println("a");
  }
  File dir = new File("/storage/emulated/0/webIDE/temp");
  adbCommandExe("node -v",dir);
}
String sketchPath(String path){
  return getContext().getFilesDir().getAbsolutePath()+"/"+path;
}
void addEnv(ProcessBuilder pb,String e,String value){
  Map<String, String> env = pb.environment();
  env.put(e,value);
}
private String adbCommandExe(String command,File dir) {
  StringBuilder suilder = new StringBuilder();
  ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
  if(dir!=null)processBuilder.directory(dir);
  addEnv(processBuilder,"LD_LIBRARY_PATH",sketchPath("lib"));
  addEnv(processBuilder,"PATH",sketchPath("bin"));
  addEnv(processBuilder,"LANG","en_US.UTF-8");
  InputStream iStream = null;
  InputStreamReader isReader = null;
  try {
    Process proc = processBuilder.start();
    iStream = proc.getInputStream();
    isReader = new InputStreamReader(iStream);
    BufferedReader bufferedReader = new BufferedReader(isReader);
    String line;
    while ((line = bufferedReader.readLine()) != null) {
      suilder.append(line);
      suilder.append("\n");
      println(line);
    }
    BufferedReader br = new BufferedReader(new InputStreamReader(proc.getErrorStream())); 
    while ((line = br.readLine()) != null) { 
      suilder.append(line);
      suilder.append("\n");
      println(line);
    }
  }
  catch(Exception e) {
    e.printStackTrace();
  } 
  finally {
    try {
      if (iStream != null) {
        iStream.close();
      }
      if (isReader != null) {
        isReader.close();
      }
    } 
    catch(Exception e) {
      e.printStackTrace();
    }
  }
  return suilder.toString();
}
private boolean isDirectory(final String path) throws IOException { 
  AssetManager assetManager = getActivity().getResources().getAssets();
  boolean isDirectory = false;
  try {
    if (assetManager.list(path).length > 0) {
      isDirectory = true;
    } else {
      assetManager.open(path);
    }
  }
  catch (FileNotFoundException fnfe) {
    isDirectory = true;
  }
  return isDirectory;
}
private void copyFiles(final String parentPath, final String filename, final File toDir) throws IOException {
  AssetManager assetManager = getActivity().getResources().getAssets();
  String assetpath = (parentPath != null ? parentPath + File.separator + filename : filename);
  if (isDirectory(assetpath)) {
    if (!toDir.exists()) {
      toDir.mkdirs();
    } 
    for (String child : assetManager.list(assetpath)) {
      copyFiles(assetpath, child, new File(toDir, child));
    }
  } else {
    copyData(assetManager.open(assetpath), new FileOutputStream(new File(toDir.getParentFile(), filename)));
  }
}
private void copyData(InputStream input, FileOutputStream output) throws IOException {
  int DEFAULT_BUFFER_SIZE = 1024 * 4; 	
  byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; 	
  int n = 0; 		
  while (-1 != (n = input.read(buffer))) { 
    output.write(buffer, 0, n);
  } 		
  output.close(); 		
  input.close();
}
```

#あとがき
androidのjava(processing)からnode.jsを動かすの解説は以上となります
できましたでしょうか