Android应用程序通过JNI访问C库,我们要在开发板上控制led,需要实现这几个函数
- jni文件
ledCtrl(int which,int status) //控制led亮灭
ledOpen() //
ledClose() - HardControl.java java文件
声明native方法 在对应的hardcontrol.c实现对应的C函数 
1. 新建HardControl.java,编写代码
package com.example.ndk.ndk.hardlibrary;
public class HardControl {
    public static native int ledCtrl(int which, int status);
    public static native int ledOpen();
    public static native void ledClose();
    static {
        try {
            System.loadLibrary("hardcontrol");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
 
- 打包的就是当前的目录
 - 定义一个类HardControl,声明几个native方法,native修饰方法,表示只能调用不能修改,static 表示外部可以直接调用方法
 - 在类中定义静态代码块,加载C库,只在第一次被实例化时调用一次
 - 选中加载C库语句,Ctrl+Alt+T 增加异常处理代码
 
2. 编写JNI文件,加载so文件
编写Hardcontrol.c文件
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <android/log.h>  //android offer print library
#if 0
typedef struct {
	char *name;
	char* signature;
	void* fnPtr;
}JNINativeMethod;
#endif
jint ledOpen(JNIEnv* env, jobject cls)
{
	__android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native led_open...");
	return 0;
}
void ledClose(JNIEnv* env, jobject cls)
{
	__android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native led_close...");
}
jint ledCtrl(JNIEnv* env, jobject cls, jint which, jint status)
{
	__android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledCtrl:%d,%d", which, status);
	return 0;
}
static const JNINativeMethod methods[] = {
		{"ledOpen", "()I", (void*)ledOpen},
		{"ledClose", "()V", (void*)ledClose},
		{"ledCtrl", "(II)I", (void*)ledCtrl},
};
/* System.loadLibrary */
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM* jvm, void* reserved)
{
	JNIEnv* env;
	jclass cls;
	if ((*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_4)) {
		return JNI_ERR; /* JNI version not supported */
	}
	cls = (*env)->FindClass(env, "com/example/ndk/ndk/hardlibary/HardControl");
	if (cls == NULL) {
		return JNI_ERR;
	}
	/* 2. map java hello <-->c c_hello */
	if ((*env)->RegisterNatives(env, cls, methods, sizeof(methods) / sizeof(methods[0])) < 0)
		return JNI_ERR;
		return JNI_VERSION_1_4;
}
 
GCC 生成动态链接库so文件
arm-linux-gcc -fPIC -shared Hardcontrol.c -o libhardcontrol.so
 

 在app/libs下新建armeabi子目录,放入so文件
 
 修改 build.gradle,表示so文件放在lib目录下边
sourceSets{
		main{
			jniLibs.srcDirs = ['libs']
		}
	}
 
如下:
 
 连接开发板,编译运行,错误
 Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1936]: 1266 could not load needed library ‘libgcc_s.so.1’ for ‘libhardcontrol.so’ (load_library[1091]: Library ‘libgcc_s.so.1’ not found)
 说明libhardcontrol.so依赖于libgcc_s.so.1,看开发板中有没有这个库
 
- 在Android源码目录下查找libc.so find -name “libc.so”

-nostdlib 表示在生成so文件时,不会自动使用标准libc库,我们可以指定使用哪个libc 
arm-linux-gcc -fPIC -shared Hardcontrol.c -o libhardcontrol.so -I /usr/lib/jvm/java-7-openjdk-amd64/include -nostdlib /work/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/libc.so -I /work/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/include/
 
注意:这里要加上两个头文件路径-I,不然编译会包如下错误
 
 
 编译后的放到android studio中,执行报错,dlopen时找不到__android_log_print函数,所以编译so的时候需要添加库,在android源码中搜索:find -name “liblog*”
 
 
 所以最终编译命令如下:
arm-linux-gcc -fPIC -shared Hardcontrol.c -o libhardcontrol.so -I /usr/lib/jvm/java-7-openjdk-amd64/include -nostdlib /work/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/libc.so -I /work/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/include/ /work/android-5.0.2/prebuilts/ndk/9/platforms/android-5/arch-arm/usr/lib/liblog.so
 
3. 在MainActivity.java
package com.example.ndk.ndk.app_0001_leddemo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import com.example.ndk.ndk.hardlibrary.HardControl;
public class MainActivity extends AppCompatActivity {
    private Button button = null;
    private boolean ledon = false;
    private CheckBox checkBoxLed1 = null;
    private CheckBox checkBoxLed2 = null;
    private CheckBox checkBoxLed3 = null;
    private CheckBox checkBoxLed4 = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.BUTTON);
        // 调用native接口打开led
        HardControl.ledOpen();
        checkBoxLed1 = (CheckBox)findViewById(R.id.LED1);
        checkBoxLed2 = (CheckBox)findViewById(R.id.LED2);
        checkBoxLed3 = (CheckBox)findViewById(R.id.LED3);
        checkBoxLed4 = (CheckBox)findViewById(R.id.LED4);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ledon = !ledon;
                if (ledon)
                {
                    button.setText("ALL OFF");
                    checkBoxLed1.setChecked(true);
                    checkBoxLed2.setChecked(true);
                    checkBoxLed3.setChecked(true);
                    checkBoxLed4.setChecked(true);
                    //点亮4个led
                    for(int i = 0; i < 4; i ++) {
                        HardControl.ledCtrl(i,1);
                    }
                } else {
                    button.setText("ALL OFF");
                    checkBoxLed1.setChecked(false);
                    checkBoxLed2.setChecked(false);
                    checkBoxLed3.setChecked(false);
                    checkBoxLed4.setChecked(false);
                    for(int i = 0; i < 4; i ++) {
                        HardControl.ledCtrl(i,0);
                    }
                }
            }
        });
    }
    //4个checkbox共用一个onCheckboxClicked方法
    public void onCheckboxClicked(View view) {
        //是否被按下
       boolean checked = ((CheckBox)view).isChecked();
       switch (view.getId()) {
           case R.id.LED1:
               if (checked) {
                   HardControl.ledCtrl(0,1);
               } else {
                   HardControl.ledCtrl(0,0);
               }
               break;
           case R.id.LED2:
               if (checked) {
                   HardControl.ledCtrl(1,1);
               } else {
                   HardControl.ledCtrl(1,0);
               }
               break;
           case R.id.LED3:
               if (checked) {
                   HardControl.ledCtrl(2,1);
               } else {
                   HardControl.ledCtrl(2,0);
               }
               break;
           case R.id.LED4:
               if (checked) {
                   HardControl.ledCtrl(3,1);
               } else {
                   HardControl.ledCtrl(3,0);
               }
               break;
       }
    }
}
 
在itop4412上运行效果
 点击按钮或复选框都会在AndroidStudio中打印信息
 










