android JNI執行NDK編譯成的可執行檔案
阿新 • • 發佈:2019-01-10
1.android環境的可執行檔案的生成
所謂的android下的可執行檔案,其實就是一般的c/c++程式碼使用NDK編譯出來的應用程式。它和linux下用gcc編譯出來的程式和windows系統下的.exe檔案是一樣的。要將程式碼編譯成可執行檔案只需要將編譯so的include $(BUILD_SHARED_LIBRARY)改成include $(BUILD_EXECUTABLE)就行。
Main.cpp
#include <iostream> #include <android/log.h> using namespace std; #define LOG_TAG "JNI_LOG" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) int main(int argc, char **argv) { LOGI("NativeFile Begin!"); LOGI("This is a Test!"); LOGI("NativeFile End!"); return 0; }
Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
Main.cpp
LOCAL_MODULE := NativeFile
LOCAL_LDLIBS := -llog
include $(BUILD_EXECUTABLE)
Application.mk
APP_PLATFORM = android-8
APP_ABI := armeabi
APP_STL := stlport_static
2.android 應用使用JNI執行NDK編譯的可執行檔案.
1) 將上面生成的NativeFile可執行檔案放在android工程的asset目錄下面。
2) 將asset中的可執行檔案拷貝到應用的data空間中。
3)使用linux的fork函式建立子程序,並使用execlp執行可執行檔案.
4)此時apk所在的程序和可執行檔案的程序分屬於二個不同的程序,擁有不同的程序id,所以就算APK檔案解除安裝了以後這個可執行檔案還是在執行狀態的,這樣我們的應用就可以在apk被解除安裝了以後仍然能做很多的事情,比如向360一樣顯示一個解除安裝調查的網頁,或者傳送應用被解除安裝的訊息給自己的伺服器等等。
下面附上程式碼.
MainActivity.java
package com.example.testnative; import android.app.Activity; import android.app.ActionBar; import android.app.Fragment; import android.content.res.AssetManager; import android.os.Bundle; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.os.Build; public class MainActivity extends Activity { static { System.loadLibrary("TestNative"); } native void ExecFile(AssetManager asset,String path); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ExecFile(getAssets(),getCacheDir().toString()); } }
TestNative.cpp
#include <jni.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <android/log.h>
#include <time.h>
#include <utime.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/wait.h>
extern "C"
{
#define LOG_TAG "JNI_LOG"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
char* Jstring2String(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes",
"(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0)
{
rtn = (char*) malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
}
void ExecChildProcess(const char* fileName, const char* param)
{
LOGI("Begin ExecCmdByChildProcess!\n");
pid_t pid = fork();
if (pid == 0)
{
pid_t pid2 = fork();
if (pid2 == 0)
{
if (execlp(fileName, fileName, param, NULL) < 0)
LOGI("ExecChildProcess %s error!\n", fileName);
exit(0);
}
else
{
exit(0);
}
}
else if (pid > 0)
{
int status = 0;
waitpid(pid, &status, 0);
}
else
{
LOGE("ExecChildProcess Error!\n");
}
}
void Java_com_example_testnative_MainActivity_ExecFile(JNIEnv* env, jobject obj,
jobject asset, jstring path)
{
AAssetManager* asMg = AAssetManager_fromJava(env, asset);
AAsset* as = AAssetManager_open(asMg, "NativeFile", AASSET_MODE_UNKNOWN);
char* tmp = Jstring2String(env, path);
char cPath[256] =
{ 0 };
strcpy(cPath, tmp);
strcat(cPath, "/NativeFile");
free(tmp);
if (as != NULL)
{
int len = AAsset_getLength(as);
LOGI("len=%d", len);
int file = open(cPath, O_WRONLY | O_CREAT, 0755);
char* buf = new char[1024];
while (len > 0)
{
int n = AAsset_read(as, buf, 1024);
if (n < 0)
break;
write(file, buf, n);
len -= n;
}
delete[] buf;
AAsset_close(as);
close(file);
}
ExecChildProcess(cPath, " ");
}
}
執行APK後的結果: