① android jni程序(c++)如何編譯適用於arm-v8指令集的32位程序
可以看到Android上層的Application和ApplicationFramework都是使用java編寫,
底層包括系統和使用眾多的LIiraries都是C/C++編寫的。
所以上層Java要調用底層的C/C++函數庫必須通過Java的JNI來實現。
下面將學習Android是如何通過Jni來實現Java對C/C++函數的調用。以HelloWorld程序為例:
第一步:
使用Java編寫HelloWorld 的Android應用程序:
package com.lucyfyr;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class HelloWorld extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.v("fresne", printJNI("I am HelloWorld Activity"));
}
static
{
//載入庫文件
System.loadLibrary("HelloWorldJni");
}
//聲明原生函數 參數為String類型 返回類型為String
private native String printJNI(String inputStr);
}
這一步我們可以使用eclipse來生成一個App;
因為eclipse會自動為我們編譯此Java文件,後面要是用到。
第二步:
生成共享庫的頭文件:
進入到eclipse生成的Android Project中 :/HelloWorld/bin/classes/com/lucyfyr/
下:
可以看到裡面後很多後綴為.class的文件,就是eclipse為我們自動編譯好了的java文件,其中就有:
HelloWorld.class文件。
退回到classes一級目錄:/HelloWorld/bin/classes/
執行如下命令:
javah com.lucyfyr.HelloWorld
生成文件:com_lucyfyr_HelloWorld.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_lucyfyr_HelloWorld */
#ifndef _Included_com_lucyfyr_HelloWorld
#define _Included_com_lucyfyr_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_lucyfyr_HelloWorld
* Method: printJNI
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_lucyfyr_HelloWorld_printJNI
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
可以看到自動生成對應的函數:Java_com_lucyfyr_HelloWorld_printJNI
Java_ + 包名(com.lucyfyr) + 類名(HelloWorld) + 介面名(printJNI):必須要按此JNI規范來操作;
java虛擬機就可以在com.simon.HelloWorld類調用printJNI介面的時候自動找到這個C實現的Native函數調用。
當然函數名太長,可以在.c文件中通過函數名映射表來實現簡化。
第三步:
實現JNI原生函數源文件:
新建com_lucyfyr_HelloWorld.c文件:
#include <jni.h>
#define LOG_TAG "HelloWorld"
#include <utils/Log.h>
/* Native interface, it will be call in java code */
JNIEXPORT jstring JNICALL Java_com_lucyfyr_HelloWorld_printJNI(JNIEnv *env, jobject obj,jstring inputStr)
{
LOGI("fresne Hello World From libhelloworld.so!");
// 從 instring 字元串取得指向字元串 UTF 編碼的指針
const char *str =
(const char *)(*env)->GetStringUTFChars( env,inputStr, JNI_FALSE );
LOGI("fresne--->%s",(const char *)str);
// 通知虛擬機本地代碼不再需要通過 str 訪問 Java 字元串。
(*env)->ReleaseStringUTFChars(env, inputStr, (const char *)str );
return (*env)->NewStringUTF(env, "Hello World! I am Native interface");
}
/* This function will be call when the library first be load.
* You can do some init in the libray. return which version jni it support.
*/
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
void *venv;
LOGI("fresne----->JNI_OnLoad!");
if ((*vm)->GetEnv(vm, (void**)&venv, JNI_VERSION_1_4) != JNI_OK) {
LOGE("fresne--->ERROR: GetEnv failed");
return -1;
}
return JNI_VERSION_1_4;
}
OnLoadJava_com_lucyfyr_HelloWorld_printJNI
函數裡面做一些log輸出 注意JNI中的log輸出的不同。
JNI_OnLoad函數JNI規范定義的,當共享庫第一次被載入的時候會被回調,
這個函數裡面可以進行一些初始化工作,比如注冊函數映射表,緩存一些變數等,
最後返回當前環境所支持的JNI環境。本例只是簡單的返回當前JNI環境。
http://www.cnblogs.com/bastard/archive/2012/05/19/2508913.html
② 安卓修改 framework jni 後怎麼編譯
JNI對性能的提升沒有我預想中的大,對於for循環的速度提升大概在1倍左右,所以如果數量級不大的話,性能提升不會很明顯 JNI編完之後,不能調試,是不是很蛋疼,不像android Java可以看出錯信息。
③ jni編譯問題
這個是警告,不影響使用,說要求參數是const char*的,你傳的參數只是char*,
對嚴格要求的時候可以考慮轉換const char*
④ Android用NDK和整套源碼下編譯JNI的不同
2. 注冊函數的方法是不同的。舉例說,在com/evan129/jnitest/jniutils.java有個native int foo()方法,需要在jni中實現
在ndk中,只要實現這個函數,然後函數名是以jint java_com_evan129_jnitest_jniutils_foo(jnienv* env, jobject thiz) 命名既可。也就是說,如果jni只要實現這個函數,並且功能也很簡單的話,那麼jni c/cpp文件里只需要這一個函數就完事了。
但在android源碼中編譯jni代碼是不同的,jni中的函數名無所謂。不過至少還需要加一個
jniexport jint jnicall jni_onload(javavm* vm, void* reserved)方法,這個方法可以找個現有的復制一把就行,檢查運行環境的。然後主要是這個方法中會調用(*env).registernatives函數,在這里把jni中的方法和java文件中的方法關聯起來。
3. 有個很詭異的區別,自動傳入的jnienv* env好像不是一個東西。因為在android源碼中使用這個env一般是如env->newstringutf(…),而ndk中sample里的一處是(*env)->newstringutf(…) 這env和*env差很大。但兩處函數傳入的都是jnienv* env,只能懷疑jnienv的定義是不是都是不同的。
⑤ android studio 怎麼編譯jni
一、使用已經編譯好的so
這種情況比較件簡單,只要把的.so文件放到相應的目錄即可。如下:
.[mole_name]
. . [src]
. . .[main]
. . . .[jniLibs]
. . . . .[armeabi]
. . . . .[armeabi-v7a]
. . . . .[x86]
. . . . .[mips]
注意 jniLibs 目錄是放在 mole 下面,在Android Studio中效果如下,這樣編譯之後so就會被自動打包進apk,代碼中直接 loadLibrary即可了:
1 String libName = "helloNDK"; // 庫名, 注意沒有前綴lib和後綴.so
2 System.loadLibrary( libName );
二、使用C/C++源碼
1 r9d以上版本NDK
首先確保自己的NDK版本在r9d以上,目前最新可以拿到的是r10,下載地址:
http://tools.android-studio.org/
感謝 Android Studio中文組的無私奉獻。
如果低於r9d版本,Android studio 下ndk編譯會出現 No rule to make target 的錯誤。
2 配置 ndk.dir
在 local.properties 添加如下配置:
sdk.dir=/path/to/android-sdk
ndk.dir=/path/to/android-ndk
⑥ android studio JNI開發時 編譯成功 但是沒有生成.so文件 什麼原因
1
在交叉編譯的時候怎麼都無法生成so文件,javah生成頭文件沒錯,c文件也沒錯,java文件也沒錯,
2.原因:是JNI文件夾路徑不對
3
在執行javah命令時,我進入的是cd
app/src/main/java
這樣jni文件夾在java文件夾下,作為一個包存在,這樣就無法生成so文件
執行javah的正確姿勢:
4
進入app/src/main目錄:cd
app/src/main
執行javah命令:javah
javah
-d
jni
-classpath
./Java
lab.sodino.jnitest.MainActivity
5,
-d
jni
頭文件生成到jni文件夾(當前在<Project>\app\src\main目錄下,所以.h所在的目錄為<Project>\app\src\main\jni
)
-classpath
./java
指定去當前路徑下java下尋找包名指定的類
這樣再rebuild一下,就會生成so文件了
⑦ android jni怎麼編譯
參考如下
打開Eclipse,選擇菜單 "File->New->other...";
選擇「Android->Android Project from Existing Code」後,點擊 Next;
① 點擊"Browse..."按鈕,選擇"ndk根目錄下->samples->hello-jni",如目錄是「D:\Android\android-ndk-r9d\samples\hello-jni」;
② 取消「Project:->Project to import->tests」的復選框;
③ 選中「Copy projects into workspace」
④ 然後點擊 Finish 完成
① 選擇「「HelloJni」工程後點擊右鍵->Android Tools->Add Native Support...」;
② 在 "Add Android Native Support" 界面點擊 Finish
打開工程文件 「hellojni->jni->hello-jni.c",發現報錯:」Method 'NewStringUTF' could not be resolved「;解決方法:
①將 文件名」hello-jni.c「改為」hello-jni.cpp「;
②將文件」hello-jni.cpp「中的
函數 」Java_com_example_hellojni_HelloJni_stringFromJNI「的最前面加上"extern C"
③將文件」hello-jni.cpp「中的
函數 」Java_com_example_hellojni_HelloJni_stringFromJNI「
的最後一行的代碼:
」return (*env)->NewStringUTF(env, "Hello from JNI ! Compiled with ABI " ABI ".");「
改為
」return env->NewStringUTF("Hello from JNI ! Compiled with ABI " ABI ".");「
④在工程文件"hellojni->jni->Android.mk」中的
「LOCAL_SRC_FILES := hello-jni.c」改為「LOCAL_SRC_FILES := hello-jni.cpp」
⑤點擊工具欄上的按鈕 Build All(Ctrl+B),或者使用快捷鍵"Ctrl+B"
⑥改為後的文件內容如下:
點擊工程"hellojni右鍵->Debug As->Andrid Native Application;結果報錯:
「Unable to resolve target 'android-3'」,解決方法:
打開工程文件「hellojni->AndroidManifest.xml」選擇」Manifest分頁->Manifest Extras->Uses SDK「,修改右邊」Atributes for User Sdk「下的「Min SDK Version」為19, 「Target SDK Version"為19, (註:19是android4.4.2版,目前最新版),保存;
保存後又發現錯誤提示」Avoid hardcoding the debug mode;「,解決方法:」打開AndroidManifest.xml文件Application分頁「,將"Application Attributes"下的 Debuggable 屬性框中的 true 清除掉;
點擊工程"hellojni右鍵->Debug As->Andrid Native Application;運行結構
⑧ 如何在Android下使用JNI
關於如何在Android使用JNI調用C/C++代碼庫,網上已經有很多優秀的文章了,這里說一個大概過程吧:
首先需要懂C,其次要明白JNI的開發流程,然後還要知道NDK如何使用
1、在java代碼中聲明了一個native本地方法
Public native String helloFromc();
2、在項目目錄中創建JNI文件夾
3、在JNI文件夾裡面創建C文件,按照規范寫代碼
Jstring
Java_com_cheng_jnitest_MainActivity_helloFromc(JNIEnv* env,jobject obj)
4、用ndk-build指令編譯
編譯前需要配置Android.mk文件
//指定編譯的文件夾,指定當前的目錄
LOCAL_PATH := $(call my-dir)
//編譯器在編譯的時候會產生很多臨時變數,中間變數最好在編譯前清空所有的臨時變數
include $(CLEAR_VARS)
//編譯完成後的模塊名
LOCAL_MOUDLE := hello
//編譯的源文件
LOCAL_SRC_FILES:=hello.c
//編譯一個動態庫
//動態庫.so 只包含運行的函數,不包含依賴,所以體積小,運行的時候回去系統尋找依賴
//靜態庫.a 包含所有的函數和運行的依賴,所以體積大,包含所有的api
include $(BUILD_SHARED_LIBRARY)
5、生成了一個so動態庫,放到了libs裡面
6、項目中引入依賴庫
Static{
System.loadLibrary("hello");
}
⑨ java jni 怎麼在windows環境中編譯成linux下的so文件
可以直接在android工程下使用,因為android就是linux內核。
android的NDK開發需要在linux下進行: 因為需要把C/C++編寫的代碼生成能在arm上運行的.so文件,這就需要用到交叉編譯環境,而交叉編譯需要在linux系統下才能完成。
2.安裝android-ndk開發包,這個開發包可以在google android : 通過這個開發包的工具才能將android jni 的C/C++的代碼編譯成庫
3.android應用程序開發環境: 包括eclipse、java、 android sdk、 adt等。
NDK編譯步驟:
選擇 ndk 自帶的例子 hello-jni ,位於E:android-ndk-r5sampleshello-jni( 根據具體的安裝位置而定 ) 。
2.運行 cygwin ,輸入命令 cd /cygdrive/e/android-ndk-r5/samples/hello-jni ,進入到 E:android-ndk-r5sampleshello-jni 目錄。
3.輸入 $NDK/ndk-build ,執行成功後,它會自動生成一個 libs 目錄,把編譯生成的 .so 文件放在裡面。 ($NDK是調用我們之前配置好的環境變數, ndk-build 是調用 ndk 的編譯程序 )
4.此時去 hello-jni 的 libs 目錄下看有沒有生成的 .so 文件,如果有,ndk 就運行正常啦。
⑩ 如何編譯 hello jni
2打開Eclipse,選擇菜單 "File->New->other...";
3選擇「Android->Android Project from Existing Code」後,點擊 Next;
4 ① 點擊"Browse..."按鈕,選擇"ndk根目錄下->samples->hello-jni",如我的目錄是「D:\Android\android-ndk-r9d\samples\hello-jni」;
② 取消「Project:->Project to import->tests」的復選框;
③ 選中「Copy projects into workspace」
④ 如下圖,後點擊 Finish 完成
5 ① 選擇「「HelloJni」工程後點擊右鍵->Android Tools->Add Native Support...」;
② 在 "Add Android Native Support" 界面點擊 Finish
6 打開工程文件 「hellojni->jni->hello-jni.c",發現報錯:」Method 'NewStringUTF' could not be resolved「;如下圖所示;解決方法:
①將 文件名」hello-jni.c「改為」hello-jni.cpp「;
②將文件」hello-jni.cpp「中的
函數 」Java_com_example_hellojni_HelloJni_stringFromJNI「的最前面加上"extern C"
③將文件」hello-jni.cpp「中的
函數 」Java_com_example_hellojni_HelloJni_stringFromJNI「
的最後一行的代碼:
」return (*env)->NewStringUTF(env, "Hello from JNI ! Compiled with ABI " ABI ".");「
改為
」return env->NewStringUTF("Hello from JNI ! Compiled with ABI " ABI ".");「
④在工程文件"hellojni->jni->Android.mk」中的
「LOCAL_SRC_FILES := hello-jni.c」改為「LOCAL_SRC_FILES := hello-jni.cpp」
⑤點擊工具欄上的按鈕 Build All(Ctrl+B),或者使用快捷鍵"Ctrl+B"
⑥改為後的文件內容如下:
7點擊工程"hellojni右鍵->Debug As->Andrid Native Application;結果報錯:
「Unable to resolve target 'android-3'」,解決方法:
打開工程文件「hellojni->AndroidManifest.xml」選擇」Manifest分頁->Manifest Extras->Uses SDK「,修改右邊」Atributes for User Sdk「下的「Min SDK Version」為19, 「Target SDK Version"為19, (註:19是android4.4.2版,目前最新版),保存;
8保存後又發現錯誤提示」Avoid hardcoding the debug mode;「,解決方法:」打開AndroidManifest.xml文件Application分頁「,將"Application Attributes"下的 Debuggable 屬性框中的 true 清除掉;如下:(註:更好對這個問題的解決方法見我網路經驗);
9點擊工程"hellojni右鍵->Debug As->Andrid Native Application;運行結構
10至此已經完成,如果還有疑問可以留言哦