Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Studio使用JNI調用C代碼

Android Studio使用JNI調用C代碼

編輯:關於Android編程

一、配置NDK環境

第一步:在AndroidStudio中配置ndk環境

需要下載ndk包,在AndroidStudio中File-->ProjectStructure-->SDK Location中配置"Android NDK Location",如下:   \   下載安裝完成後build工程;  

第二步:配置環境變量

在計算機屬性裡面配置環境變量,變量地址是Android NDK Location裡面的路徑:(我這裡是:C:\studio\android-sdk-windows\ndk-bundle)   \
   

第三步:測試環境變量是否配置成功

在CMD裡面輸入ndk-build,如果未提示"ndk-build不是系統命令"就表示NDK環境配置完成了!  

二、編譯JNI生成So包並調用

 

第一步:生成調用方demo

java代碼MainActivity.java:
public class MainActivity extends Activity {

    static {
        System.loadLibrary("JniTest");
    }

    public native String getStringFromNative();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView txt = (TextView) findViewById(R.id.main_txt_msg);
        txt.setText(getStringFromNative());
    }
}

xml代碼"activity_main.xml":



    

    


 

第二步:配置build.gradle

在app文件夾下的build.gradle文件裡面配置Ndk相關信息
        ndk {
            moduleName "JniTest"
            ldLibs "log", "z", "m"
            abiFilters "armeabi", "armeabi-v7a", "x86"
        }
    sourceSets{
        main{
            jniLibs.srcDirs = ['libs']
        }
    }
\  

第三步:生成與調用方有關的.h文件(C頭文件)

在Android Studio下方的Terminal命令行裡面執行生成命令,如果沒有Terminal,到"View->Tool Windows->Terminal"裡面打開該面板 操作命令:
javah -d jni -classpath ; 加載So所在的class包名+class名
後面的" 加載So所在的class包名+class名"是相對於你當前所在目錄的路徑;   參考命令:
C:\git_source\demo\JniTest>javah -d jni -classpath C:\studio\android-sdk-windows\platforms\android-23\android.jar;app\src\main\java com.example.jni.jnitest.MainActivity
這裡的後面一部分是相對於"C:\git_source\demo\JniTest"目錄的路徑   命令執行成功會自動生成一個jni文件夾和對應的"包名.h"文件,這裡的文件名是:com_example_jni_jnitest_MainActivity.h \  

第四步:編寫C代碼

C代碼"main.c":
/* DO NOT EDIT THIS FILE - it is machine generated */  
#include   
#include   
  
#ifndef LOG_TAG  
#define LOG_TAG "ANDROID_LAB"  
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)  
#endif  

/* Header for class com_example_jni_jnitest_MainActivity */
  
#ifndef _Included_com_example_jni_jnitest_MainActivity
#define _Included_com_example_jni_jnitest_MainActivity
#ifdef __cplusplus  
extern "C" {  
#endif  
/* 
 * Class: com_example_jni_jnitest_MainActivity
 * Method: getStringFromNative 
 * Signature: ()Ljava/lang/String; 
 */  
JNIEXPORT jstring JNICALL Java_com_example_jni_jnitest_MainActivity_getStringFromNative(JNIEnv * env, jobject jObj){
      return (*env)->NewStringUTF(env,"Hello From JNI!");  
  }
  
#ifdef __cplusplus  
}  
#endif  
#endif  

注意,你需要將com_example_jni_jnitest_MainActivity_getStringFromNative替換成你工程裡面對應的方法路徑
   

第五步:編寫Android.mk文件和Application.mk文件

  前面第一步的圖裡面可以看到jni包裡面多了一個Android.mk文件和Application.mk文件,還有一個main.c文件是上一步我們生成的 Android.mk文件和Application.mk文件是用來控制編譯So文件的,Android.mk文件控制So文件如何編譯, Application.mk文件控制支持的架構平台.   Android.mk文件:
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
#bzlib模塊
bzlib_files := \
	main.c

LOCAL_MODULE := libbz
LOCAL_SRC_FILES := $(bzlib_files)
include $(BUILD_STATIC_LIBRARY)

#bspath模塊
include $(CLEAR_VARS)
LOCAL_MODULE    := main
LOCAL_SRC_FILES := main.c
LOCAL_STATIC_LIBRARIES := libbz #引入libbz庫

include $(BUILD_STATIC_LIBRARY)

include $(CLEAR_VARS)

LOCAL_MODULE    := JniTest
LOCAL_SRC_FILES := main.c
LOCAL_STATIC_LIBRARIES := main
LOCAL_LDLIBS := -llog#加入log

include $(BUILD_SHARED_LIBRARY)
"bzlib_files :"裡面放的是所有的c源文件;"LOCAL_MODULE := JniTest"表示生成的So庫名,因為我加載So庫的名字是"JniTest"所以這裡需要同名;
static {
        System.loadLibrary("JniTest");
    }
Application.mk文件:
APP_CFLAGS += -Wno-error=format-security
APP_ABI := armeabi
APP_ABI := armeabi 表示只支持armeabi架構的Jni,如需添加其他架構可在後面追加  

第六步:編譯So文件

在CMD命令行裡面cd到項目的目錄下, 輸入"ndk-build"生成So包 \   命令執行成功後在工程的libs文件夾下面生成一個So文件,如下: \ 如果不添加Application.mk文件,會生成所有架構的So文件,如下: \   編譯出來的So默認是放在工程裡面的libs文件夾下的,需要將它移到app文件夾下的libs裡面!  

第七步:打包運行

運行代碼,查看結果: \   這裡打印出了C代碼返回的值,Jni的調用就成功了!    

三、遇到的問題與解決

 

問題一:找不到mk文件

\
\

原因是JniTest項目裡面的jni目錄下沒有Android.mk文件

 

問題二:couldn't find "libJniTest.so"說找不到so文件(這裡是libJniTest.so)

FATAL EXCEPTION: main
Process: com.example.jni.jnitest, PID: 30152
java.lang.UnsatisfiedLinkError: com.android.tools.fd.runtime.IncrementalClassLoader$DelegateClassLoader[DexPathList[[dex file "/data/data/com.example.jni.jnitest/files/instant-run/dex/slice-support-annotations-23.4.0_d560f708638dfceb3917510f1cc1dc667f754e94-classes.dex", dex file "/data/data/com.example.jni.jnitest/files/instant-run/dex/slice-slice_9-classes.dex", dex file "/data/data/com.example.jni.jnitest/files/instant-run/dex/slice-slice_8-classes.dex", dex file "/data/data/com.example.jni.jnitest/files/instant-run/dex/slice-slice_7-classes.dex", dex file "/data/data/com.example.jni.jnitest/files/instant-run/dex/slice-slice_6-classes.dex", dex file "/data/data/com.example.jni.jnitest/files/instant-run/dex/slice-slice_5-classes.dex", dex file "/data/data/com.example.jni.jnitest/files/instant-run/dex/slice-slice_4-classes.dex", dex file "/data/data/com.example.jni.jnitest/files/instant-run/dex/slice-slice_3-classes.dex", dex file "/data/data/com.example.jni.jnitest/files/instant-run/dex/slice-slice_2-classes.dex", dex file "/data/data/com.example.jni.jnitest/files/instant-run/dex/slice-slice_1-classes.dex", dex file "/data/data/com.example.jni.jnitest/files/instant-run/dex/slice-slice_0-classes.dex", dex file "/data/data/com.example.jni.jnitest/files/instant-run/dex/slice-internal_impl-23.4.0_00c09662b55d223b900e647a021f5f9dd9b4b6e9-classes.dex", dex file "/data/data/com.example.jni.jnitest/files/instant-run/dex/slice-com.android.support-support-vector-drawable-23.4.0_8b8204428df1954e75ed14d23129e230d51e4401-classes.dex", dex file "/data/data/com.example.jni.jnitest/files/instant-run/dex/slice-com.android.support-support-v4-23.4.0_ab900e8ce412421b38e4e809122c4e820ea3b15b-classes.dex", dex file "/data/data/com.example.jni.jnitest/files/instant-run/dex/slice-com.android.support-appcompat-v7-23.4.0_60d063a4fe66aa6d98c8e4fbd0183a230d80c604-classes.dex", dex file "/data/data/com.example.jni.jnitest/files/instant-run/dex/slice-com.android.support-animated-vector-drawable-23.4.0_7565542ff4cab32ab703cc056ccf47fe61af9054-classes.dex"],nativeLibraryDirectories=[/vendor/lib64, /system/lib64, /vendor/lib64, /system/lib64]]] couldn't find "libJniTest.so"
    at java.lang.Runtime.loadLibrary(Runtime.java:378)
    at java.lang.System.loadLibrary(System.java:998)
    at com.example.jni.jnitest.MainActivity.(MainActivity.java:11)
    at java.lang.reflect.Constructor.newInstance(Native Method)
    at java.lang.Class.newInstance(Class.java:1572)
    at android.app.Instrumentation.newActivity(Instrumentation.java:1068)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2303)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2466)
    at android.app.ActivityThread.access$1200(ActivityThread.java:152)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1341)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5538)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:958)
第一步:需要在app的build.gradle裡面的Android{}裡面添加如下代碼,指定jni放置目錄:
    sourceSets{
        main{
            jniLibs.srcDirs = ['libs']
        }
    }

第二步:然後將so文件放在app文件夾下的libs裡面

\ 第三步:編譯運行  
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved