Android JNI开发一: 如何生成SO库
Posted 长沙火山
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android JNI开发一: 如何生成SO库相关的知识,希望对你有一定的参考价值。
目录
Android JNI开发二: SO库的使用
一、JNI
1.1 创建工程
用 androidStudio 创建一个新的工程,我的 AndroidStudio 版本为4.2.2。创建工程第一步的时候,需要选择模版,请选择 Native C++ 这个模版。这个模版为我们提供了JNI开发的环境,我们在这个模版里可以更容易的使用JNI 去调用C语言代码。
(1) 创建工程第一步:选择 Native C++ 模版,如下图所示:
(2) 创建工程第二步:填写项目名称、项目存放目录,如下图所示:
(3) 创建工程第三步:选择语言版本,选择默认的即可,如下图所示:
至此,项目创建完毕,项目中CPP目录就是编写C语言代码的地方。整个目录如下图所示:
1.2 下载JNI相关工具
打开 SDK Manager 对话框, AndroidStudio -> Tools -> SDK Manager,如下图所示:
下载 NDK 和CMake 工具,如下图所示:
1.3 编写C语言代码
接下来,我们要做一个简单的计算器,实现最基本的加法、减法、乘法、除法。加减乘除的计算功能用C语言实现,界面控件布局等则用 Java语言实现,然后采用 JNI 的方式去调用C语言里的加减乘除方法。
(1) 在和 MainActivity 同级目录下新建一个 java 类,类名为:JNITools。
package com.example.jnidemo;
public class JNITools {
// 这个链接C语言文件的代码本来是在MainActivity里面,我挪到了这里来了,照做即可。
static {
System.loadLibrary("native-lib");
}
//自己添加加减乘除四个方法的声明,具体实现在native-lib.cpp文件里。
public static native int addNumber(int a, int b);
public static native int subNumber(int a, int b);
public static native int mulNumber(int a, int b);
public static native int divNumber(int a, int b);
}
(2) 在 native-lib.cpp 里面实现加减乘除方法。
添加完上面四个方法之后,会发现四个方法都变红了。因为只是声明了方法,没有实现方法,所以当然会报错。不过不要慌,将这四个方法实现一下即可。将鼠标移动到飙红的方法上面,然后 Alt + Enter,会发现代码正常了。这个时候,我们点开 native-lib.cpp 文件,会发现系统自动帮我们实现了这个方法,只是方法体里面是空的,需要自己去实现你想要的业务逻辑。
敲黑板,重点来了。 到了这里,有的同学可能会感觉奇怪,为什么我在JNITools里面声明方法,方法的具体实现却跑到了native-lib.cpp文件里。因为仔细看上面的代码,是这句代码 System.loadLibrary("native-lib");
把这两个文件关联到了一起。在ios里面有头文件和源文件之分,JNITools.java 就相当于头文件,native-lib 就相当于源文件。
打开 native-lib.cpp,在方法体里面添加自己的业务逻辑代码:
#include <jni.h>
#include <string>
extern "C"
JNIEXPORT jint JNICALL
Java_com_example_jnidemo_MainActivity_sum(JNIEnv *env, jobject thiz, jint a, jint b) {
return a+b;
}extern "C"
JNIEXPORT jint JNICALL
Java_com_example_jnidemo_JNITools_addNumber(JNIEnv *env, jclass clazz, jint a, jint b) {
return a+b;
}extern "C"
JNIEXPORT jint JNICALL
Java_com_example_jnidemo_JNITools_subNumber(JNIEnv *env, jclass clazz, jint a, jint b) {
return a-b;
}extern "C"
JNIEXPORT jint JNICALL
Java_com_example_jnidemo_JNITools_mulNumber(JNIEnv *env, jclass clazz, jint a, jint b) {
return a*b;
}extern "C"
JNIEXPORT jint JNICALL
Java_com_example_jnidemo_JNITools_divNumber(JNIEnv *env, jclass clazz, jint a, jint b) {
return a/b;
}
至此,我们的C语言代码就写好了。JNITools里的方法是提供给安卓代码调用的,native-lib.cpp里面的代码最终会被编译成so库。
1.4 安卓代码调用C语言
下面,就回到了安卓这部分,这部分都是大家比较熟悉的,就加快进度直接上代码。
(1) activity_main.xml 里添加布局代码:
package com.example.jnidemo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.example.jnidemo.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btnAdd,btnSub,btnMul,btnDiv;
private EditText inputA,inputB;
private TextView tvResult;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupView();
addListener();
}
private void addListener() {
btnAdd.setOnClickListener(this);
btnDiv.setOnClickListener(this);
btnMul.setOnClickListener(this);
btnSub.setOnClickListener(this);
}
private void setupView() {
btnAdd=this.findViewById(R.id.add);
btnDiv=this.findViewById(R.id.div);
btnMul=this.findViewById(R.id.mul);
btnSub=this.findViewById(R.id.sub);
inputA=this.findViewById(R.id.inputa);
inputB=this.findViewById(R.id.inputb);
tvResult=this.findViewById(R.id.result);
}
@Override
public void onClick(View v) {
double result=0;
String strA=inputA.getText().toString();
String strB=inputB.getText().toString();
int a=Integer.parseInt(strA);
int b=Integer.parseInt(strB);
switch (v.getId()){
case R.id.add:
result=JNITools.addNumber(a,b);
break;
case R.id.div:
result=JNITools.divNumber(a,b);
break;
case R.id.mul:
result=JNITools.mulNumber(a,b);
break;
case R.id.sub:
result=JNITools.subNumber(a,b);
break;
}
tvResult.setText(""+result);
}
}
(2) string.xml 里添加代码:
<resources>
<string name="app_name">JniDemo</string>
<string name="add">相加</string>
<string name="sub">相减</string>
<string name="mul">相乘</string>
<string name="div">相除</string>
</resources>
(3) MainActivity 里添加代码:
package com.example.jnidemo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btnAdd,btnSub,btnMul,btnDiv;
private EditText inputA,inputB;
private TextView tvResult;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupView();
addListener();
}
private void addListener() {
btnAdd.setOnClickListener(this);
btnDiv.setOnClickListener(this);
btnMul.setOnClickListener(this);
btnSub.setOnClickListener(this);
}
private void setupView() {
btnAdd=this.findViewById(R.id.add);
btnDiv=this.findViewById(R.id.div);
btnMul=this.findViewById(R.id.mul);
btnSub=this.findViewById(R.id.sub);
inputA=this.findViewById(R.id.inputa);
inputB=this.findViewById(R.id.inputb);
tvResult=this.findViewById(R.id.result);
}
@Override
public void onClick(View v) {
double result=0;
String strA=inputA.getText().toString();
String strB=inputB.getText().toString();
int a=Integer.parseInt(strA);
int b=Integer.parseInt(strB);
//这里就是通过JNI调用C语言的代码
switch (v.getId()){
case R.id.add:
result=JNITools.addNumber(a,b);
break;
case R.id.div:
result=JNITools.divNumber(a,b);
break;
case R.id.mul:
result=JNITools.mulNumber(a,b);
break;
case R.id.sub:
result=JNITools.subNumber(a,b);
break;
}
tvResult.setText(""+result);
}
}
(4) 运行效果
1.5 生成SO库
前面就提到过native-lib.cpp最终会被编译成so库,提供给普通的安卓程序使用。那么怎么将native-lib.cpp编译成so库呢?其实so库被存放在apk里面了,解压apk文件,即可得到so库。
以上是关于Android JNI开发一: 如何生成SO库的主要内容,如果未能解决你的问题,请参考以下文章