androidjni調用過程
① 如何在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");
}
② android studio怎麼調用jni
(1)老版本,方法如下: task NativeLibs(type: Copy) { from(new File(project(':MyProject').buildDir, 'native-libs')) { include '**/*.so' } into new File(buildDir, 'native-libs') } tasks.withType(Compile) { compileTask -> compileTask.dependsOn NativeLibs } clean.dependsOn 'cleanCopyNativeLibs' tasks.withType(com.android.build.gradle.PackageApplicationTask) { pkgTask -> pkgTask.jniDir new File(buildDir, 'native-libs') } (2)新版本三種方法: (2.1)打包前先生成.Jar文件後自動解包到apk文件 task nativeLibsToJar(type: Zip, description: 'create a jar archive of the native libs') { destinationDir file("$buildDir/native-libs") baseName 'native-libs' extension 'jar' from fileTree(dir: 'libs', include: '**/*.so') into 'lib/' } tasks.withType(Compile) { compileTask -> compileTask.dependsOn(nativeLibsToJar) } 下面一句話就是打包生成目錄(build\native-libs)中的.jar文件 compile fileTree(dir: "$buildDir/native-libs", include: 'native-libs.jar') (2.2)手動生成.Jar文件後自動解包到apk文件 這個方式需要自己手動進行.SO文件壓縮,具體步驟為:將所有需要使用的.so文件壓縮為.zip文件(zip中的文件目錄結構為: lib/armeabi/*.so)然後把zip文件後綴改為.Jar然後放到libs生成apk就ok 默認就是自動打包所有.Jar文件: dependencies { compile fileTree(dir: 'libs', include: '*.jar') } (2.3)這也就是現在正在使用的方式(推薦) ,其實無非就是把.SO文件打包到APK的lib文件夾中,假如仔細閱讀了Gradle的使用方法,自然就知道其實Gradle官方在新版已經自動實現了打包.SO文件的.很簡單級就是在配置的android節點下加入下面的內容就ok: sourceSets { main { jniLibs.srcDirs = ['libs'] } } 其他地方無需修改,整個項目的配置文件如下: apply plugin: 'android' android { compileSdkVersion 19 buildToolsVersion "19.0.0" defaultConfig { minSdkVersion 16 targetSdkVersion 19 versionCode 1 versionName "1.0" } buildTypes { release { runProguard false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' } } sourceSets { main { jniLibs.srcDirs = ['libs'] } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) }
③ android studio ndk怎麼調用
android studio ndk調用過程如下:
通過jniaes案例說明調用NDK層配置過程
而我們通過底層來判斷簽名是否正確,如果正確則繼續執行核心代碼,否則退出程序,這樣就可以防止別人惡意反編譯,並進行二次打包。
首先去官網下載一個最新的NDK,隨便放到哪都行,像我放在D:DevAndroidandroid-ndk-r10d.
(1) 新建一個項目:名稱JniAes
首先在java類中添加native介面,注意寫好native介面和System.loadLibrary()即可。代碼如下:
1 public synchronized static native String getFromNativeIv();
2 public synchronized static native String getStringFromNative();
3 public synchronized static native int jniCheckAPP(Context context);
4
然後build project得到其中中間文件,我們關注的是.class文件。編譯OK以後生成的class文件在AS工程的如下目錄:
aesapp
(2)接下來跟class文件生成相應的.h頭文件,執行如下命令即可
點擊"View->Tool Windows->Terminal" 即在Studio中進行終端命令行工具.執行如下命令生成c語言頭文件.
javah -d jni -classpath c:
android-16android.jar;....uildintermediatesclassesdebug com.aes.jniaes.MainActivity
(3)然後將剛才的 .h文件剪切過來。在jni目錄下新建一個c文件,隨意取名,我的叫strk.c 。
strk.c文件,用於實現核心代碼邏輯,判斷包名.哈希值是否合法,如果返回1,為合法。反之,則不合法。入口方法為:
jint Java_com_aes_jniaes_MainActivity_jniCheckAPP(JNIEnv* env, jobject context,
jobject thiz)
接下來在工程的local.properties文件中添加NDK路徑(上面下載好的那個NDK),類似其中的SDK路徑一樣,我的添加後如下:
sdk.dir=D:\Dev\Android\android-sdk-windows
ndk.dir=D:\Dev\Android\android-ndk-r10d
(4)接下來在app mole目錄下的build.gradle中設置庫文件名(生成的so文件名)。找到gradle文件的defaultConfig這項,在裡面添加如下內容:
defaultConfig {
applicationId "com.aes.jniaes"
minSdkVersion 15
targetSdkVersion 22
versionCode 1
versionName "1.0"
ndk {
moleName "checkapp-jni" //生成的so名字
abiFilters "armeabi", "armeabi-v7a", "x86" //輸出指定三種abi體系結構下的so庫。目前可有可無。
}
}
(5)最後就是添加靜態初始化loadLibrary代碼,添加如下:
static {
System.loadLibrary("checkapp-jni"); //so文件的名字
}
編譯出來的so文件在aesappuildintermediates dkdebuglib目錄下
那麼如何將編譯好的so文件進行使用,可以通過如下方式:
二 .引用so文件
(1).在「src/main」目錄中新建名為「jniLibs」的目錄;
(2).將so文件復制、粘貼到「jniLibs」目錄內。
④ 如何在android下使用jni
第一步:
使用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環境。第四步:
編譯生成so庫
編譯com_lucyfyr_HelloWorld.c成so庫可以和app一起編譯,也可以都單獨編譯。
在當前目錄下建立jni文件夾:HelloWorld/jni/
下建立Android.mk ,並將com_lucyfyr_HelloWorld.c和 com_lucyfyr_HelloWorld.h 拷貝到進去
編寫編譯生成so庫的Android.mk文件:復制代碼
LOCAL_PATH:= $(call my-dir)
# 一個完整模塊編譯
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=com_lucyfyr_HelloWorld.c
LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
LOCAL_MODULE := libHelloWorldJni
LOCAL_SHARED_LIBRARIES := libutils
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_TAGS :=optional
include $(BUILD_SHARED_LIBRARY)
復制代碼
系統變數解析:
LOCAL_PATH - 編譯時的目錄
$(call 目錄,目錄….) 目錄引入操作符
如該目錄下有個文件夾名稱 src,則可以這樣寫 $(call src),那麼就會得到 src 目錄的完整路徑
include $(CLEAR_VARS) -清除之前的一些系統變數
LOCAL_MODULE - 編譯生成的目標對象
LOCAL_SRC_FILES - 編譯的源文件
LOCAL_C_INCLUDES - 需要包含的頭文件目錄
LOCAL_SHARED_LIBRARIES - 鏈接時需要的外部庫
LOCAL_PRELINK_MODULE - 是否需要prelink處理
include$(BUILD_SHARED_LIBRARY) - 指明要編譯成動態庫
⑤ android中,請簡述jni的調用過程
1)安裝和下載Cygwin,下載 Android NDK
2)在ndk項目中JNI介面的設計
3)使用C/C++實現本地方法
4)JNI生成動態鏈接庫.so文件
5)將動態鏈接庫復制到java工程,在java工程中調用,運行java工程即可
⑥ android中如何調用jni需要ndk嗎
ndk是一個可以在android開發工具上面開發C或者c++的插件,所以是需要的,調用jni需要在java代碼裡面聲明一個native方法,然後在c或者c++裡面實現那個方法,編譯成.so庫文件,在需要使用的地方調用。
⑦ android jni 怎麼實現
Android中JNI是編譯so庫的源代碼,編譯成功後會生成SO庫,android中最終是使用SO庫的。
1.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編譯步驟:
1.選擇 ndk 自帶的例子 hello-jni ,我的位於E:\android-ndk-r5\samples\hello-jni( 根據具體的安裝位置而定 ) 。
2.運行 cygwin ,輸入命令 cd /cygdrive/e/android-ndk-r5/samples/hello-jni ,進入到 E:\android-ndk-r5\samples\hello-jni 目錄。
3.輸入 $NDK/ndk-build ,執行成功後,它會自動生成一個 libs 目錄,把編譯生成的 .so 文件放在裡面。 ($NDK是調用我們之前配置好的環境變數, ndk-build 是調用 ndk 的編譯程序 )
4.此時去 hello-jni 的 libs 目錄下看有沒有生成的 .so 文件,如果有,ndk 就運行正常啦。
⑧ 如何在android studio中用JNI調用靜態庫
androidstudiondk調用過程如下:通過jniaes案例說明調用NDK層配置過程而我們通過底層來判斷簽名是否正確,如果正確則繼續執行核心代碼,否則退出程序,這樣就可以防止別人惡意反編譯,並進行二次打包。首先去官網下載一個最新的NDK,隨便放到哪都行,像我放在D:\Dev\Android\android-ndk-r10d.(1)新建一個項目:名稱JniAes首先在java類中添加native介面,注意寫好native介面和System.loadLibrary()即可。代碼如下:();();(Contextcontext);4然後buildproject得到其中中間文件,我們關注的是.class文件。編譯OK以後生成的class文件在AS工程的如下目錄:aes\app\build\intermediates\classes\debug\android\(2)接下來跟class文件生成相應的.h頭文件,執行如下命令即可點擊"View->ToolWindows->Terminal"即在Studio中進行終端命令行工具.執行如下命令生成c語言頭文件.javah-djni-classpathc:\Users\sodinochen\AppData\Local\Android\sdk\platforms\android-16\android.jar;..\..\build\intermediates\classes\debugcom.aes.jniaes.MainActivity(3)然後將剛才的.h文件剪切過來。在jni目錄下新建一個c文件,隨意取名,我的叫strk.c。strk.c文件,用於實現核心代碼邏輯,判斷包名.哈希值是否合法,如果返回1,為合法。反之,則不合法。入口方法為:jintJava_com_aes_jniaes_MainActivity_jniCheckAPP(JNIEnv*env,jobjectcontext, jobjectthiz)接下來在工程的local.properties文件中添加NDK路徑(上面下載好的那個NDK),類似其中的SDK路徑一樣,我的添加後如下:sdk.dir=D\:\\Dev\\Android\\android-sdk-windowsndk.dir=D\:\\Dev\\Android\\android-ndk-r10d(4)接下來在appmole目錄下的build.gradle中設置庫文件名(生成的so文件名)。找到gradle文件的defaultConfig這項,在裡面添加如下內容:defaultConfig{ applicationId"com.aes.jniaes" minSdkVersion15 targetSdkVersion22 versionCode1 versionName"1.0" ndk{ moleName"checkapp-jni" //生成的so名字 abiFilters"armeabi","armeabi-v7a","x86" //輸出指定三種abi體系結構下的so庫。目前可有可無。 } }(5)最後就是添加靜態初始化loadLibrary代碼,添加如下:static{ System.loadLibrary("checkapp-jni"); //so文件的名字 }編譯出來的so文件在aes\app\build\intermediates\ndk\debug\lib目錄下 那麼如何將編譯好的so文件進行使用,可以通過如下方式:二. 引用so文件(1).在「src/main」目錄中新建名為「jniLibs」的目錄;(2).將so文件復制、粘貼到「jniLibs」目錄內。
⑨ android怎麼用APK調用JNI簡單實例
製作Android的內置APK,調用C或者C++去調用底層介面:
環境配置:
eclipse要配置NDK插件和系統環境,我用的是WIN7,先去下載NDK,解壓後就是一個目錄,把路徑記住,去XP電腦配置下環境,就像配置Java環境一樣,把路徑寫到系統環境的PATH就好了(這樣就可以編譯JNI了)。然後在配置eclipse的NDK插件,點擊eclipse的WINDOW/PREFERNCES,彈出框了後點擊android/NDK,有個路徑選擇,一樣選擇你下載好解壓的目錄(選擇後提示不是有效的NDK目錄的時候,你在NDK目錄裡面新建一個文件,名字寫:ndk-build,沒有後綴)
http://blog.csdn.net/csh86277516/article/details/52639023
⑩ 如何調用 androidruntime中注冊的jni
千鋒扣丁學堂Android開發學習為您解答: Android系統運用Java語言,而Java語言的數據基本中沒有無符號類型,Android系統下底層發送的信息一般是「\n\r」的機制。開始做項目時候,兩條路一條是運用ADB做項目,另一條是運用JNI和ADB做項目,前期使用運用ADB做項目,運用兩個類Runtime and Process.其中把操作串口的執行C文件通過ADB工具放入Android系統的system目錄下。在運用Android上層應用框架層控制並運行項目。從中出現問題,那就是項目失敗率比較高,而項目是直接面對客服的,無法讓客服對這一切滿足。後面就開發了另外一條運用JNI和ADB,解決上述問題,保證成功升級。 JNI能解決Java沒有C program無符號類型的問題,通過把JNI與Java的調用解決問題,Java無法直接操作和控制Linux內核層的串口,而C語言可以,在Android 系統層存在lib庫,裡麵包含C語言庫,打包成動態鏈接庫so文件,Android系統上層可以直接調用動態鏈接庫so文件。 Android系統下底層發送的信息一般是「\n\r」,而Android系統外接設備不接受 「\n\r」數據,這樣也會導致項目的失敗。經過實驗對Android 系統的串口參數進行設置,把Android系統下底層發送的信息附帶「\n\r」給過濾,如此一來就解決問題。