一:從應用層向下編譯so庫 html
若是你尚未安裝NDK:java
https://developer.android.com/ndk/downloads/index.html#stable-downloads
解壓獲得android-ndk-r15c目錄,記住路徑。主要須要它下面的ndk目錄及文件。android
~/.bash_profile
文件,加入這樣一行(要用到上面的解壓路徑):PATH=$PATH:/Downloads/android-ndk-r15c/ndk
而後,執行source ~/.bash_profile
,使之生效。bash
ln -s /Downloads/android-ndk-r15c/ndk ndk
這樣就設置好了。app
命名爲FactorialDemo,接下來的選項所有默認便可。ide
1-1.png函數
1-2.png佈局
1-3.png測試
1-4.pnggradle
把視圖切換到Project,下圖中標記出來的是要修改的幾個文件,固然咱們還要建立幾個文件:
1-5.png
2-1.png
內容以下:
package ai.nixie.aiden.factorialdemo; public class Factorial { public static long fac(long n){ return n <=0? 1 : n * fac(n-1); } public native static long facNTV(long n); }
點擊窗口下方的Terminal
,打開命令行窗口,切換到app/src/main/目錄,而後執行命令生成頭文件。
cd app/src/main/ javah -jni -classpath java/ -d jni/ ai.nixie.aiden.factorialdemo.Factorial
注意:
ai.nixie.aiden.factorialdemo.Factorial
前面ai.nixie.aiden.factorialdemo
是package包名,所有小寫
。最後的Factorial
是上面建立的Factorial的類名
,注意區分大小寫
哦!不然會報錯。
執行結果以下圖。
3-1.png
若是沒有看到任何提示,說明運行成功啦。
這時再看左側的項目樹,發現多一個jni
文件夾,展開裏面就是咱們剛生成的頭文件啦。
3-2.png
如今選中ai_nixie_aiden_factorialdemo_Factorial.h
文件,按Command + C
複製,接着按Command + V
粘貼,彈出以下對話框。
把文件名最後的h
改成c
。點OK
。
如今的jni
文件夾就有2個文件了。
4-2.png
接下來修改C文件(ai_nixie_aiden_factorialdemo_Factorial.c
)的內容爲:
#include <ai_nixie_aiden_factorialdemo_Factorial.h> static jlong fac(long n) { return n<=0 ? 1 : n * fac(n - 1); } JNIEXPORT jlong JNICALL Java_ai_nixie_aiden_factorialdemo_Factorial_facNTV (JNIEnv *env, jclass clazz, jlong n){ return fac(n); };
Android.mk
文件在jni
文件夾下新建一個文件,名字爲Android.mk
,內容以下:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES :=ai_nixie_aiden_factorialdemo_Factorial.c LOCAL_MODULE :=ai_nixie_aiden_factorialdemo_Factorial include $(BUILD_SHARED_LIBRARY)
Application.mk
文件在jni
文件夾下新建一個文件,命名爲Application.mk
,內容以下:
APP_PLATFORM := android-14 APP_ABI :=all
若是不加的話,會提示Android NDK: APP_PLATFORM not set. Defaulting to minimum supported version android-14.
點擊右上角出現的Sync Now
。
6-1.png
so
庫文件此時,在Terminal窗口中執行ndk-build
,就能夠獲得編譯的so文件。
若是如今就編譯整個項目,會獲得下面的錯誤。
8-1.png
8-2.png
在jni
文件夾下的任意文件上右擊,選擇Link C++ Project with Gradle
。
8-3.png
選擇ndk-build
,並找到並選擇它的Android.mk
文件,而後OK。
8-4.png
執行完這一步後,在build.gradle
文件中android下面多了幾行:
externalNativeBuild { ndkBuild { path 'src/main/jni/Android.mk' } }
其實直接在這個文件中加入這幾行應該就能夠了。
在Factorial.java文件中,加入導入庫文件的代碼,
static { System.loadLibrary("ai_nixie_aiden_factorialdemo_Factorial"); }
完成後以下:
package ai.nixie.aiden.factorialdemo; public class Factorial { public static long fac(long n){ return n <=0? 1 : n * fac(n-1); } public native static long facNTV(long n); static { System.loadLibrary("ai_nixie_aiden_factorialdemo_Factorial"); } }
好了,如今先測試一下,應該能夠正常編譯了。不過咱們如今尚未在咱們的APP中用上so庫的功能。
9-1.png
9-2.png
修改res/layout/activity_main.xml
文件,改成LinearLayout
佈局,加入3個控件,一個輸入框用於輸入數字,一個文本框用於顯示結果,一個按鈕。
完成後以下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <EditText android:id="@+id/input" android:text="5" android:textSize="32dp" android:textAlignment="center" android:selectAllOnFocus="true" android:inputType="text" android:maxLines="1" android:layout_width="match_parent" android:layout_height="wrap_content"> <requestFocus /> </EditText> <TextView android:id="@+id/result" android:textSize="32dp" android:textAlignment="center" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="result" /> <Button android:id="@+id/calculate" android:text="Calculate" android:textSize="32dp" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
主要的幾個修改點:
修改完成的MainActivity.java文件爲:
package ai.nixie.aiden.factorialdemo; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.text.TextUtils; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private EditText inputBox; private TextView tvResult; private Button calButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); inputBox = (EditText) findViewById(R.id.input); tvResult = (TextView) findViewById(R.id.result); calButton = (Button) findViewById(R.id.calculate); calButton.setOnClickListener(this); } @Override public void onClick(View view) { String in = inputBox.getText().toString(); if (TextUtils.isEmpty(in)) { return; } long input = Long.parseLong(in); /* These two lines are the most important! */ Factorial myFactorial = new Factorial(); long result = myFactorial.facNTV(input); /* These two lines are the most important! */ tvResult.setText(String.format("fac(%d)=%d", input, result)); } }
其中最主要的是這2句:
Factorial myFactorial = new Factorial(); //生成一個Factorial類的實例, long result = myFactorial.facNTV(input); //而後調用它的facNTV或fac方法,來計算階乘。
到此項目完成。實際的運行結果圖:
11-1.png
完成後的項目樹:
11-2.png
二:直接用ndk-build編譯so庫
當咱們有C文件須要編譯成so庫時,在工程新建一jni目錄,將C文件複製到這個目錄下,而後在添加一個Android.mk文件,其中須要這幾行
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := led //生成so庫的名字 LOCAL_SRC_FILES := ledjni.c //C文件的名字 include $(BUILD_SHARED_LIBRARY)
而後cmd進入jni目錄下,ndk-build編譯便可。編譯完成後會在當前目錄下生成一個 libs文件夾,裏面存放的是編譯好的so庫。