Размещение исполняемого файла в приложении Android
Я работаю над приложением для Android, которое зависит от двоичного файла ELF: наш Java-код взаимодействует с этим двоичным файлом для выполнения задач. Эта среда выполнения должна запускаться и завершаться при запуске приложения и выходе из приложения / по требованию.
Вопросы:
Я предполагаю, что мы сможем выполнить этот двоичный файл, используя Runtime.exec() API. Есть ли какие-либо ограничения относительно того, куда мне нужно поместить мою библиотеку в структуре папок? Как системная среда выполнения найдет этот исполняемый файл? Есть ли какая-то настройка пути к классу?
Поскольку приложение зависит от этой среды выполнения, я думал обернуть его вокруг службы, чтобы его можно было запускать или останавливать по мере необходимости. Каков наилучший способ обработки таких исполняемых файлов в Android Project?
Каковы другие альтернативы, при условии, что у меня нет исходного кода для этого исполняемого файла?
Пожалуйста, дайте совет.
Спасибо.
Переведено автоматически
Ответ 1
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 ). Если вы планируете поддерживать службу, которая выполняет ваш cammand, имейте в виду, что службы могут быть остановлены и перезапущены Android в любой момент.
3) Теперь, если у вас нет исходного кода, я надеюсь, что ваш файл, по крайней мере, скомпилирован как исполняемый файл arm. Если нет, я не понимаю, как вы вообще могли бы его запустить.
Вы запустите файл, выполнив следующие команды в вашем классе java:
Я ничего не знаю о вашем исполняемом файле, поэтому вам может понадобиться, а может и не понадобиться на самом деле получать InputStream и OutputStream.
Из приложения Android Java, используя assets папку
Включите двоичный файл в папку assets.
ИспользуйтеgetAssets().open(FILENAME), чтобы получить InputStream.
Запишите его в /data/data/APPNAME (например, /data/data/net.gimite.nativeexe), где у вашего приложения есть доступ для записи файлов, и сделайте его исполняемым.
Запустите /system/bin/chmod 744 /data/data/APPNAME/FILENAME, используя приведенный выше код.
Запустите свой исполняемый файл, используя приведенный выше код.
В сообщении используется assets папка вместо raw папки, которую Android предлагает для статических файлов:
Совет: Если вы хотите сохранить статический файл в своем приложении во время компиляции, сохраните файл в каталоге project res / raw / . Вы можете открыть его с помощью openRawResource(), передав идентификатор R.raw. resource . Этот метод возвращает InputStream, который вы можете использовать для чтения файла (но вы не можете выполнить запись в исходный файл).
Конечно, все это следует выполнять только один раз после установки. Вы можете выполнить быструю проверку внутри onCreate() или что-то еще, что проверяет наличие файла и выполняет все эти команды, если файла там нет.
Дайте мне знать, если это сработает. Удачи!
Ответ 2
Вот полное руководство по упаковке и запуску исполняемого файла. Я основал его на том, что нашел здесь, и других ссылках, а также на своих собственных пробах и ошибках.
1.) В вашем проекте SDK поместите исполняемый файл в папку / assets
2.) Программно получаем строку этого каталога файлов (/data /данные /имя__аппликации/файлы) следующим образом
3.) В Java-коде проекта вашего приложения: скопируйте исполняемый файл из папки / assets в подпапку "files" вашего приложения (обычно /data / данные / имя__приложения / файлы) с помощью функции, подобной этой:
privatevoidcopyAssets(String filename) {
AssetManagerassetManager= getAssets();
InputStreamin=null; OutputStreamout=null; Log.d(TAG, "Attempting to copy this file: " + filename); // + " to: " + assetCopyDestination);
try { in = assetManager.open(filename); Log.d(TAG, "outDir: " + appFileDirectory); FileoutFile=newFile(appFileDirectory, filename); out = newFileOutputStream(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.) Измените права доступа к файлу executable_file, чтобы он действительно стал исполняемым. Сделайте это с помощью вызовов Java:
Обратите внимание, что для любых файлов, упомянутых здесь (таких как входные и выходные файлы), должны быть сконструированы полные строки пути. Это связано с тем, что это отдельный созданный процесс, и он не имеет понятия о том, что такое "pwd".
Если вы хотите прочитать стандартный вывод команды, вы можете это сделать, но пока у меня это работает только для системных команд (например, "ls"), а не для исполняемого файла:
Выполнение двоичного файла, начиная с Android 10, возможно только из папки, доступной только для чтения. Это означает, что вы должны упаковать двоичный файл в свое приложение. Android doc
Поместить android:extractNativeLibs="true" в AndroidManifest;
Поместите свой двоичный файл в src/main/resources/lib/* каталог, где * – обозначает архитектуру процессора, например, armeabi-v7a;
Вот обсуждение с ответом от команды Android на reddit.
Ответ 4
Я сделал что-то подобное с помощью NDK. Моя стратегия заключалась в том, чтобы перекомпилировать программу с помощью NDK и написать некоторый JNI-код-оболочку, который вызывал функцию main программы.
Я не уверен, на что похож жизненный цикл кода NDK. Даже службы, которые предназначены для длительной работы, могут запускаться и останавливаться системой, когда это удобно. Вероятно, вам придется завершить работу вашего потока NDK и перезапустить его при необходимости.