0
点赞
收藏
分享

微信扫一扫

Android应用程序访问c库

西红柿上校 2022-02-23 阅读 130

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中打印信息
在这里插入图片描述

举报

相关推荐

0 条评论