二、Android应用程序访问C库

Android应用程序通过JNI访问C库,我们要在开发板上控制led,需要实现这几个函数

  • JNI文件
    ledCtrl(int which,int status)
    ledOpen()
    ledClose()
  • HardControl.java java文件
    声明native方法 在对应的hardcontrol.c实现对应的C函数

1. 新建HardControl.java,编写代码

  • 新建HardControl.java
    在这里插入图片描述
  • 打开AS,HardControl.java,编写代码
	package com.example.hardlibary;  //打包的就是当前的目录
	
	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>  /* /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ */
	#include <stdio.h>
	#include <stdlib.h>
	 
	#if 0
	typedef struct {
	    char *name;          /* Java里调用的函数名 */
	    char *signature;    /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */
	    void *fnPtr;          /* C语言实现的本地函数 */
	} JNINativeMethod;
	#endif
	
	jint ledOpen(JNIEnv *env, jobject cls)
	{	
		return 0;
	}
	void ledClose(JNIEnv *env, jobject cls)
	{	
	}
	jint ledCtrl(JNIEnv *env, jobject cls,jint which,jint 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/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文件
    在这里插入图片描述
  • 在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
    /home/topeet/Android/iTop4412_ICS_git/prebuilt/ndk/android-ndk-r6/platforms/android-9/arch-arm/usr/lib/libc.so
  • 重新编译so文件
    在这里插入图片描述
# arm-none-linux-gnueabi-gcc -fPIC -shared hardcontrol.c -o libhardcontrol.so -I /usr/lib/jvm/jdk1.6.0_43/include/ -I /usr/lib/jvm/jdk1.6.0_43/include/linux/ -nostdlib /home/topeet/Android/iTop4412_ICS_git/prebuilt/ndk/android-ndk-r6/platforms/android-9/arch-arm/usr/lib/libc.so -I /home/topeet/Android/iTop4412_ICS_git/prebuilt/ndk/android-ndk-r5/platforms/android-9/arch-arm/usr/include /home/topeet/Android/iTop4412_ICS_git/prebuilt/ndk/android-ndk-r5/platforms/android-9/arch-arm/usr/lib/liblog.so

  • 在JNI文件中加上打印信息
#include <jni.h>  /* /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ */
#include <stdio.h>
#include <stdlib.h>
#include <android/log.h>  //android offer print library

#if 0
typedef struct {
    char *name;          /* Java里调用的函数名 */
    char *signature;    /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */
    void *fnPtr;          /* C语言实现的本地函数 */
} 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/hardlibary/HardControl");
	if (cls == NULL) {
		return JNI_ERR;
	}

	/* 2. map java hello <-->c c_hello */
	if ((*env)->RegisterNatives(env, cls, methods, 3) < 0)
		return JNI_ERR;

	return JNI_VERSION_1_4;
}
  • 编译生成so库,出现找不到头文件 的就在安卓源码中find - name “xx”,找到头文件路径,用-I指示,找不到库的,也是在源码中查找,指定需要库的路径
    在这里插入图片描述

3. 在MainActivity.java

	package com.example.myapplication;
	
	import android.support.v7.app.AppCompatActivity;
	import android.os.Bundle;
	import android.widget.Button;
	import android.view.View;
	import android.widget.CheckBox;
	import android.widget.Toast;
	import com.example.hardlibary.*;
	public class MainActivity extends AppCompatActivity {
	
	    boolean ledon = false;
	    private Button button = null;
	    private CheckBox checkBoxled1 = null;
	    private CheckBox checkBoxled2 = null;
	    private CheckBox checkBoxled3 = null;
	    private CheckBox checkBoxled4 = null;
	
	
	    class MyButtonListener implements 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);
	                for(int i= 0;i<4;i++)
	                    HardControl.ledCtrl(i,1);
	            }
	            else {
	                button.setText("ALL ON");
	                checkBoxled1.setChecked(false);
	                checkBoxled2.setChecked(false);
	                checkBoxled3.setChecked(false);
	                checkBoxled4.setChecked(false);
	                for(int i= 0;i<4;i++)
	                    HardControl.ledCtrl(i,0);
	            }
	        }
	    }
	
	    public void onCheckboxClicked(View view) {
	        // Is the view now checked?
	        boolean checked = ((CheckBox) view).isChecked();
	
	        // Check which checkbox was clicked
	        switch(view.getId()) {
	            case R.id.LED1:
	                if (checked) {
	                    Toast.makeText(getApplicationContext(), "LED1 on", Toast.LENGTH_SHORT).show();// 显示时间较短
	                    HardControl.ledCtrl(0, 1);
	                }
	                else{
	                    Toast.makeText(getApplicationContext(), "LED1 off", Toast.LENGTH_SHORT).show();// 显示时间较短
	                    HardControl.ledCtrl(0, 0);
	                }
	                break;
	            case R.id.LED2:
	                if (checked) {
	                    Toast.makeText(getApplicationContext(), "LED2 on", Toast.LENGTH_SHORT).show();// 显示时间较短
	                    HardControl.ledCtrl(1, 1);
	                }
	                else{
	                    Toast.makeText(getApplicationContext(), "LED2 off", Toast.LENGTH_SHORT).show();// 显示时间较短
	                    HardControl.ledCtrl(1, 0);
	                }
	                break;
	            case R.id.LED3:
	                if (checked) {
	                    Toast.makeText(getApplicationContext(), "LED3 on", Toast.LENGTH_SHORT).show();// 显示时间较短
	                    HardControl.ledCtrl(2, 1);
	                }
	                else{
	                    Toast.makeText(getApplicationContext(), "LED3 off", Toast.LENGTH_SHORT).show();// 显示时间较短
	                    HardControl.ledCtrl(2, 0);
	                }
	                break;
	            case R.id.LED4:
	                if (checked) {
	                    Toast.makeText(getApplicationContext(), "LED4 on", Toast.LENGTH_SHORT).show();// 显示时间较短
	                    HardControl.ledCtrl(3, 1);
	                }
	                else{
	                    Toast.makeText(getApplicationContext(), "LED4 off", Toast.LENGTH_SHORT).show();// 显示时间较短
	                    HardControl.ledCtrl(3, 0);
	                }
	                break;
	            // TODO: Veggie sandwich
	        }
	    }
	    @Override
	    protected void onCreate(Bundle savedInstanceState) {
	        super.onCreate(savedInstanceState);
	        setContentView(R.layout.activity_main);
	
	        button = (Button) findViewById(R.id.BUTTON);
	
	        HardControl.ledOpen();  //在入口函数中调用本地方法打开led,为什么可以直接调用呢个,Ctrl+B 跳转到类定义 因为ledopen是static修饰,静态方法不需要实例化对象
	        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 MyButtonListener());
	/*
	
	        button.setOnClickListener(new View.OnClickListener() {
	            public void onClick(View v) {
	                // Perform action on click
	                ledon =!ledon;
	                if(ledon)
	                    button.setText("ALL OFF");
	                else
	                    button.setText("ALL ON");
	            }
	        });*/
	    }
	}

  • 在入口函数中打开led,在按钮或复选框的响应函数中点亮或熄灭led
  • 在MainActivity.java中要用HardControl类,所以导入所在包下的文件

在itop4412上运行效果

点击按钮或复选框都会在AndroidStudio中打印信息
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AIOT技术栈

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值