Размещение исполняемого файла в приложении Android - PullRequest
28 голосов
/ 07 апреля 2011

Я работаю над приложением Android, которое зависит от двоичного файла ELF: наш Java-код взаимодействует с этим двоичным файлом для достижения цели. это время запуска должно быть запущено и завершено при запуске приложения и выход из приложения / по запросу.

Вопросы:

  1. Я предполагаю, что мы сможем выполнить этот двоичный файл, используя Runtime.exec () API. Есть ли какие-либо ограничения относительно того, где я нужно поместить мою библиотеку в структуру папок? Как система во время выполнения обнаружит этот исполняемый файл? Есть ли какая-то настройка пути к классам?

  2. Поскольку приложение имеет зависимости от этой среды выполнения, я был думать об обертывании вокруг службы, чтобы она могла быть запущена или остановился по мере необходимости. Каков наилучший способ обработки таких исполняемых файлов в проекте Android?

  3. Какие есть другие альтернативы, если предположить, что у меня нет исходного кода для этого исполняемого файла?

Пожалуйста, совет.

Спасибо.

Ответы [ 3 ]

41 голосов
/ 13 апреля 2011

1) Нет, не должно быть никаких ограничений, кроме тех, которые обращаются к системным файлам и, следовательно, требуют root.Лучшее место было бы прямо к / data / data / [your_package_name], чтобы избежать загрязнения в другом месте.

2) Очень подробное обсуждение компиляции для нативных библиотек можно найти здесь: http://www.aton.com/android-native-libraries-for-java-applications/.Другой вариант - кросс-компилятор для arm (вот тот, который используется для компиляции ядра, он бесплатный: http://www.codesourcery.com/sgpp/lite/arm).Если вы планируете поддерживать службу, которая выполняет вашу команду, имейте в виду, что службы могут быть остановлены и перезапущены Android в любой момент.

3) Теперь, если у вас нет исходного кода, я надеюсь, что ваш файл по крайней мере скомпилирован как исполняемый файл arm.Если нет, я не вижу, как ты мог бы даже запустить его.


Вы запустите файл, выполнив следующие команды в своем классе Java:

String myExec = "/data/data/APPNAME/FILENAME";
Process process = Runtime.getRuntime().exec(myExec);
DataOutputStream os = new DataOutputStream(process.getOutputStream());
DataInputStream osRes = new DataInputStream(process.getInputStream());

Я ничего не знаю о вашем исполняемом файле, поэтому вам может понадобиться или не понадобиться на самом деле получитьinputStream и outputStream.


Я предполагаю, что о запуске adb для передачи двоичного файла не может быть и речи, поэтому я искал изящный способ упаковать его.Я нашел отличный пост о включении исполняемого файла в ваше приложение.Проверьте это здесь: http://gimite.net/en/index.php?Run%20native%20executable%20in%20Android%20App

Важной частью является эта (выделение моя):

Из приложения Java для Android, используя assets папку

  • Включите двоичный файл в папку активов.
  • Используйте getAssets().open(FILENAME), чтобы получить InputStream.
  • Запишите его в /data/data/APPNAME (например, /data/data/net.gimite.nativeexe), где находится ваше приложение.имеет доступ для записи файлов и делает их исполняемыми.
  • Запустите /system/bin/chmod 744 /data/data/APPNAME/FILENAME, используя код выше.
  • Запустите свой исполняемый файл, используя код выше.

В этом посте используется папка assets, инсталяция из папки raw, которую android предлагает для статических файлов:

Совет. Если вы хотите сохранить статический файл в приложении во время компиляции,сохраните файл в вашем проекте res / raw / каталог.Вы можете открыть его с помощью openRawResource (), передавая R.raw.идентификатор ресурса.Этот метод возвращает InputStream, который вы можете использовать для чтения файла (но вы не можете записать в исходный файл).

Чтобы получить доступ к папке данных, вы можете следовать инструкциям здесь: http://developer.android.com/guide/topics/data/data-storage.html#filesInternal Кроме того, есть метод File#setExecutable(boolean);, который должен работать вместо команды оболочки.

Итак, собрав все воедино, я бы попробовал:

InputStream ins = context.getResources().openRawResource (R.raw.FILENAME)
byte[] buffer = new byte[ins.available()];
ins.read(buffer);
ins.close();
FileOutputStream fos = context.openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(buffer);
fos.close();


File file = getFileStreamPath (FILENAME);
file.setExecutable(true);

Конечно, все это нужно делать только один раз после установки.Вы можете выполнить быструю проверку внутри onCreate() или любого другого объекта, который проверяет наличие файла и выполняет все эти команды, если файла там нет.

Дайте мне знать, если он работает.Удачи!

10 голосов
/ 12 сентября 2013

Вот полное руководство по упаковке и запуску исполняемого файла. Я основал это на том, что я нашел здесь и на других ссылках, а также на моих собственных методах проб и ошибок.

1.) В своем проекте SDK поместите исполняемый файл в папку / assets

2.) Программно получить строку этого каталога файлов (/ data / data / your_app_name / files), как это

String appFileDirectory = getFilesDir().getPath();
String executableFilePath = appFileDirectory + "/executable_file";

3.) В Java-проекте проекта вашего приложения: скопируйте исполняемый файл из папки / assets в подпапку «files» вашего приложения (обычно это / data / data / your_app_name / files) с помощью такой функции:

private void copyAssets(String filename) {

AssetManager assetManager = getAssets();

InputStream in = null;
OutputStream out = null;
Log.d(TAG, "Attempting to copy this file: " + filename); // + " to: " +       assetCopyDestination);

try {
    in = assetManager.open(filename);
    Log.d(TAG, "outDir: " + appFileDirectory);
    File outFile = new File(appFileDirectory, filename);
    out = new FileOutputStream(outFile);
    copyFile(in, out);
    in.close();
    in = null;
    out.flush();
    out.close();
    out = null;
} catch(IOException e) {
Log.e(TAG, "Failed to copy asset file: " + filename, e);
} 

Log.d(TAG, "Copy success: " + filename);
}

4.) Измените права доступа к файлу для исполняемого файла, чтобы он фактически стал исполняемым. Сделайте это с вызовами Java:

File execFile = new File(executableFilePath);
execFile.setExecutable(true);

5.) Запустите файл так:

Process process = Runtime.getRuntime().exec(executableFilePath);

Обратите внимание, что для любых файлов, упомянутых здесь (например, входных и выходных файлов), должны быть созданы строки полного пути. Это потому, что это отдельный порожденный процесс, и в нем нет понятия, что такое «pwd».

Если вы хотите прочитать стандартный вывод команды, вы можете сделать это, но пока она работает только для системных команд (например, «ls»), а не для исполняемого файла:

BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
int read;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
while ((read = reader.read(buffer)) > 0) {
    output.append(buffer, 0, read);
}
reader.close();
process.waitFor();

Log.d (TAG, «output:» + output.toString ());

1 голос
/ 07 апреля 2011

Я сделал что-то подобное, используя NDK.Моя стратегия состояла в том, чтобы перекомпилировать программу с использованием NDK и написать некоторый код JNI-оболочки, который вызывается в функции программы main.

Я не уверен, как выглядит жизненный цикл кода NDK.Даже сервисы, которые предназначены для длительной работы, могут запускаться и останавливаться системой, когда это удобно.Вам, вероятно, придется закрыть нить NDK и перезапустить ее при необходимости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...