准备工作
如果你还没有安装NDK:方法(一)
- 下载,然后解压。无需安装。
https://developer.android.com/ndk/downloads/index.html#stable-downloads
解压得到android-ndk-r15c目录,记住路径。主要需要它下面的ndk目录及文件。
- 设置PATH
编辑~/.bash_profile
文件,加入这样一行(要用到上面的解压路径):
PATH=$PATH:/Downloads/android-ndk-r15c/ndk
然后,执行source ~/.bash_profile
,使之生效。
- 执行:
ln -s /Downloads/android-ndk-r15c/ndk ndk
方法(二)
1.打开 File => Project Structure 如下:
![](https://images2015.cnblogs.com/blog/804587/201703/804587-20170309092541172-1566739857.png)
![](https://images2015.cnblogs.com/blog/804587/201703/804587-20170309092801938-75896894.png)
3.在 Path 变量里添加你的 NDK路径,即上一步copy的内容,记住在路径前添加 ; 分号。
![](https://images2015.cnblogs.com/blog/804587/201703/804587-20170309092954875-1511758131.png)
1. 新建一个Android Studio项目
命名为FactorialDemo,接下来的选项全部默认即可。
![](http://upload-images.jianshu.io/upload_images/6031140-3933c8ae539c8d4f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/605)
![](http://upload-images.jianshu.io/upload_images/6031140-6b44e65a394f3382.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/379)
![](http://upload-images.jianshu.io/upload_images/6031140-ed3fe7d96f89764a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700)
![](http://upload-images.jianshu.io/upload_images/6031140-d7e92097a8ee7bce.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/646)
把视图切换到Project,下图中标记出来的是要修改的几个文件,当然我们还要创建几个文件:
![](https://upload-images.jianshu.io/upload_images/6031140-8f438672757cc9dd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/411)
2. 新建Factorial.java类
![](http://upload-images.jianshu.io/upload_images/6031140-2c79c366d2d6cf88.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/327)
内容如下:
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);
}
2.1点击 菜单 Build =>Make Project,就会编译项目,然后在
3. 从java类文件生成头文件(ai_nixie_aiden_factorialdemo_Factorial.h)
点击窗口下方的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的类名
,注意区分大小写
哦!否则会报错。
执行结果如下图。
![](http://upload-images.jianshu.io/upload_images/6031140-b45fd87f5fd3a7fd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700)
如果没有看到任何提示,说明运行成功啦。
这时再看左侧的项目树,发现多一个jni
文件夹,展开里面就是我们刚生成的头文件啦。
![](http://upload-images.jianshu.io/upload_images/6031140-b45230a21d538795.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/392)
4. 生成c文件(ai_nixie_aiden_factorialdemo_Factorial.c)
现在选中ai_nixie_aiden_factorialdemo_Factorial.h
文件,按Command + C
复制,接着按Command + V
粘贴,弹出如下对话框。
![](http://upload-images.jianshu.io/upload_images/6031140-9b028b2b597c31d8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/629)
把文件名最后的h
改为c
。点OK
。
现在的jni
文件夹就有2个文件了。
![](http://upload-images.jianshu.io/upload_images/6031140-692fd901fb4c6393.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/313)
接下来修改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);
};
注意!!!fac函数必须放在前面!顺序不能反!否则会提示找不到!
5. 编写Android.mk
文件
在jni
文件夹下新建一个文件,名字为Android.mk
,内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES :=ai_nixie_aiden_factorialdemo_Factorial.c
LOCAL_MODULE :=Factorial
include $(BUILD_SHARED_LIBRARY)
6. 编写Application.mk
文件
在jni
文件夹下新建一个文件,命名为Application.mk
,内容如下:
APP_PLATFORM := android-14
APP_ABI :=arm64-v8a armeabi-v7a
如果不加的话,会提示Android NDK: APP_PLATFORM not set. Defaulting to minimum supported version android-14.
点击右上角出现的Sync Now.
![](https://upload-images.jianshu.io/upload_images/6031140-737b609785fcc6c1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700)
7. 编译so
库文件
此时,在Terminal窗口中执行ndk-build
,就可以得到编译的so文件。
$ ndk-build
Android NDK: WARNING: APP_PLATFORM android-14 is higher than android:minSdkVersion 1 in ./AndroidManifest.xml. NDK binaries will *not* be comptible with devices older than android-14. See https://android.googlesource.com/platform/ndk/+/master/docs/user/common_problems.md for more information.
[arm64-v8a] Compile : Factorial <= ai_nixie_aiden_factorialdemo_Factorial.c
[arm64-v8a] SharedLibrary : libFactorial.so
[arm64-v8a] Install : libFactorial.so => libs/arm64-v8a/libFactorial.so
[x86_64] Compile : Factorial <= ai_nixie_aiden_factorialdemo_Factorial.c
[x86_64] SharedLibrary : libFactorial.so
[x86_64] Install : libFactorial.so => libs/x86_64/libFactorial.so
[mips64] Compile : Factorial <= ai_nixie_aiden_factorialdemo_Factorial.c
[mips64] SharedLibrary : libFactorial.so
[mips64] Install : libFactorial.so => libs/mips64/libFactorial.so
[armeabi-v7a] Compile thumb : Factorial <= ai_nixie_aiden_factorialdemo_Factorial.c
[armeabi-v7a] SharedLibrary : libFactorial.so
[armeabi-v7a] Install : libFactorial.so => libs/armeabi-v7a/libFactorial.so
[armeabi] Compile thumb : Factorial <= ai_nixie_aiden_factorialdemo_Factorial.c
[armeabi] SharedLibrary : libFactorial.so
[armeabi] Install : libFactorial.so => libs/armeabi/libFactorial.so
[x86] Compile : Factorial <= ai_nixie_aiden_factorialdemo_Factorial.c
[x86] SharedLibrary : libFactorial.so
[x86] Install : libFactorial.so => libs/x86/libFactorial.so
[mips] Compile : Factorial <= ai_nixie_aiden_factorialdemo_Factorial.c
[mips] SharedLibrary : libFactorial.so
[mips] Install : libFactorial.so => libs/mips/libFactorial.so
配置根目录下的 build.gradle 文件
![](https://images2015.cnblogs.com/blog/804587/201703/804587-20170309093505641-505226564.png)
8. 链接C++代码和Gradle
在编译整个项目的时候可能会得到下面的错误。
![](http://upload-images.jianshu.io/upload_images/6031140-1ec055bcea5b70f5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/182)
![](http://upload-images.jianshu.io/upload_images/6031140-14ff62aa2db8d6bb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/650)
在jni
文件夹下的任意文件上右击,选择Link C++ Project with Gradle
。
![](http://upload-images.jianshu.io/upload_images/6031140-667f6154eb97c270.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/450)
选择ndk-build
,并找到并选择它的Android.mk
文件,然后OK。
![](http://upload-images.jianshu.io/upload_images/6031140-e4efa9f6494def93.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/489)
执行完这一步后,在build.gradle
文件中android下面多了几行:
externalNativeBuild {
ndkBuild {
path 'src/main/jni/Android.mk'
}
}
其实直接在这个文件中加入这几行应该就可以了。
9. 导入库文件
在Factorial.java文件中,加入导入库文件的代码,
static {
System.loadLibrary("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("Factorial");
}
}
好了,现在先测试一下,应该可以正常编译了。不过我们现在还没有在我们的APP中用上so库的功能。
![](http://upload-images.jianshu.io/upload_images/6031140-fd2e793731154a14.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/182)
![](http://upload-images.jianshu.io/upload_images/6031140-cce0f1c122bccf34.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/445)
10. 完善APP,验证我们的so库
10.1 修改布局文件
修改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>
10.2 修改主java文件MainActivity.java
主要的几个修改点:
- 加入implements监听Click事件。
- 获得3个控件,并为按钮加入Click事件监听。
- 在onClick函数中,实现点击时计算阶乘的功能。其中用到了:
- 判断字符串是否为空
- String转换成Long
- 创建了Factorial的一个实例,并调用它的方法来实现阶乘的功能。
- 将阶乘的计算结果,进行字符串格式化后,显示在文本框中。
修改完成的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. 编译测试
到此项目完成。实际的运行结果图:
![](http://upload-images.jianshu.io/upload_images/6031140-70d9d665f802bbda.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/448)
完成后的项目树:
![](https://upload-images.jianshu.io/upload_images/6031140-25cc52b10346b304.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/380)
note:在配置的过程中可能会遇到的错误
1.Error:Execution failed for task ':libuvccamera:ndkClean'.
> Process 'command 'D:\AS\AndroidStudioErectionSequence\ndk-bundle/ndk-build.cmd'' finished with non-zero exit value 2
2.D:\AS\AndroidStudioEre\ndk-bundle\build\core\setup-app.mk
***Android NDK :Aborting... . Stop.
D:\AS\AndroidStudioEre\ndk-bundle\build\core\add-application.mk
***Android NDK :Aborting... . Stop.
3.或者命名不规范
解决方法:
1.gradle.propertied中添加:
#兼容老版本
android.useDeprecatedNdk=true;
链接:https://www.jianshu.com/p/7b57a19448c6
來源:简书