Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Studio--NDK編譯C代碼為.so文件,JNI調用

Android Studio--NDK編譯C代碼為.so文件,JNI調用

編輯:關於Android編程

前言:

從Android Studio開始,就支持jni和.so庫調用了。

環境:

Windows 7+Android Studio2.1.2+NDK版本:android-ndk-r10e

准備工作:

  1) ndk文件:

1,可以根據需求,從網上下載, 網址(科學上網):https://developer.android.com/ndk/downloads/index.html

2,可以查找下當前電腦是否已有ndk包,我的在目錄:

C:\ProgramData\Microsoft\AndroidNDK64\android-ndk-r10e

\

  2)配置環境變量:

選中System的path變量,進行編輯,把 ;C:\ProgramData\Microsoft\AndroidNDK64\android-ndk-r10e添加到最後,保存:

\

\

\

開始:

  Step1:新建一個項目

\

\

\

\

  Step2:添加C代碼和Android.mk文件

 Demo中我們直接使用ndk包自帶的C代碼做示例,此處我使用hello-jni的代碼:

\

a) 將jni文件夾整體copy,粘貼到main文件夾下:

\

b)在activity_main.xml中添加一個Button:




    

d)新建一個class為NdkJniUtils,在內部聲明native方法(jni使用的定義,使用關鍵字native)  

package me.jnidemo.myjnidemo;

/**
 * Created by c-yangx on 6/22/2016.
 */
public class NdkJniUtils {
    static{
        System.loadLibrary("hello-jni");//.so文件格式為:lib+庫名+.so
    }
    public static native String stringFromJNI();//函數名與C代碼的函數名保持一致
}

c)修改hello-jni.c文件中的函數名稱,格式為:Java_包名_類名_函數名(Java_me_jnidemo_myjnidemo_NdkJniUtils_stringFromJNI)

\

d) jni文件夾 右鍵=>show in Explorer 進入目錄;cmd進入此文件夾中,ndk-build命令進行編譯:

\

此編譯會觸發gradle,項目中會自動多出libs文件夾:

\

 

e)此時在MainActivity.java中添加Button的點擊事件:

package me.jnidemo.myjnidemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    TextView ev1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ev1=(TextView)findViewById(R.id.edv) ;

        Button btn=(Button)findViewById(R.id.clickId);
        btn.setOnClickListener(new Button.OnClickListener(){
            @Override
            public void onClick(View v) {
                String res=NdkJniUtils.stringFromJNI();
                ev1.setText(res);
            }
        });
    }
}

f) 在gradle.properties中添加配置:android.useDeprecatedNdk=true;

 在local.properties中添加ndk.dir=C\:\\ProgramData\\Microsoft\\AndroidNDK64\\android-ndk-r10e

 否則gradle會拋異常

g)運行,觸發click事件時,會拋異常:

06-22 15:11:04.174 7196-7196/me.jnidemo.myjnidemo E/AndroidRuntime: FATAL EXCEPTION: main
                                                                    Process: me.jnidemo.myjnidemo, PID: 7196
                                                                    java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/me.jnidemo.myjnidemo-1/base.apk"],nativeLibraryDirectories=[/vendor/lib64, /system/lib64]]] couldn't find "libhello-jni.so"
                                                                        at java.lang.Runtime.loadLibrary(Runtime.java:378)
                                                                        at java.lang.System.loadLibrary(System.java:997)
                                                                        at me.jnidemo.myjnidemo.NdkJniUtils.(NdkJniUtils.java:8)
                                                                        at me.jnidemo.myjnidemo.MainActivity$1.onClick(MainActivity.java:23)
                                                                        at android.view.View.performClick(View.java:4837)
                                                                        at android.view.View$PerformClick.run(View.java:20020)
                                                                        at android.os.Handler.handleCallback(Handler.java:739)
                                                                        at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                        at android.os.Looper.loop(Looper.java:135)
                                                                        at android.app.ActivityThread.main(ActivityThread.java:5669)
                                                                        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:960)
                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

因此我們還需進行配置----在build.gradle中做一個資源路徑指定即可:

// build.gradle
android {
//
   //...
    sourceSets {
        main {
            //你的源碼目錄
            jniLibs.srcDirs  'src/main/libs'
        }
    }
}    

重新編譯運行,ok了:

\

補錄:

  a)指定生成基於哪些CPU架構的.so文件:

1) Application.mk文件配置方式:

本文配置項,生成的為全架構平台的.so文件,缺點是會使得apk包變大:

\

可以修改,指定多個平台。如:APP_ABI :=armeabi armeabi-v7a x86 mips

 b)build.gradle配置方式:在app module目錄下的build.gradle中設置庫文件名(生成的so文件名),找到gradle文件的defaultConfig這項,在裡面添加如下內容:

defaultConfig {
    ......
    ndk{
        //moduleName "YanboberJniLibName"            //生成的so名字
        abiFilters "armeabi", "armeabi-v7a", "x86"    //輸出指定三種abi體系結構下的so庫。目前可有可無。
    }
}

  b) Android.mk配置含義:

LOCAL_PATH := $(call my-dir)     #提定當前路徑
        
include $(CLEAR_VARS)            #清除全局配置變量,LOCAL_XXX,除了LOCAL_PATH
        
LOCAL_MODULE    := hello        #指定生成動態庫名hello,生成的動態庫文件libhello.so
LOCAL_SRC_FILES := hello.c        #指定生成動態庫的源文件
        
include $(BUILD_SHARED_LIBRARY) #提定生成動態庫

 

後續:

  a) Bug 1 => app:compileDebugNdk FAILED

\

最近在研究WebRtc的APM(Audio_Processing_Module)音頻處理模塊,將所有的C代碼文件導入項目,通過ndk-build命令在cmd窗口編譯時,一切ok。

但是項目編譯時卻報此錯誤,最後(科學上網)找到了解決方案(網址:http://stackoverflow.com/questions/27453085/execution-failed-for-task-appcompiledebugndk-failed-to-run-this-command-ndk),

\

大體意思就是說gradle嘗試自己編譯你的源文件,而不是使用你編譯好的.so文件。既然在cmd中編譯通過了,那麼咱們可以通過配置,禁用gradle的ndk調用行為

,而使用你配置的路徑下的.so文件。於是,我在app build.gradle中添加了 => jni.srcDirs=[],然後編譯運行,一切ok了。

       \

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved