在Android 系统中直接调用 SO 文件

更新时间:2023-05-17 10:32:01 阅读量: 实用文档 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

在Android系统中直接调用SO文件

文/图 mangel

Android虚拟机不能直接调用底层设备,如果要对底层设备进行调用,就需要用到so使用C语言或C++编写完成,利用NDK进行编译,直接运行在Linux内核中,按jni调用so时,基本类型可以直接交互。

在apk里打包进.so文件的方法有两种,一 是在Android.mk文件里增加

“LOCAL_JNI_SHARED_LIBRARIES := libxxx”,这样在编译的时候,NDK自动会把这个libxxx打包进apk,放在xxx/lib/目录下;二是在应用的目录下手工建libs/armeabi目录,然后把libxxx.so拷贝到这个目录下,NDK也会自动把这个libxxx.so打包进apk,位置还是在xxx/lib/目录下。 在代码里,使用System.loadLibrary("xxx");就可以加载这个动态库了。这里要注意,参数只写xxx就可以了,不需要写libxxx,也不需要写libxxx.so。

还有一点要说明,System.loadLibrary这个函数会在如下路径搜索libxxx.so文件: /system/lib

/data/data/xxx apk package/lib

如果libxxx.so还依赖其它.so文件,比如libyyy.so,则System.loadLibrary只会在/system/lib目录下查找,如果没找到,不会自动到/data/data/xxx apk package/lib下去找,这个时候就会报动态库没找到的错误。解决方法是在load libxxx.so之前,先load libyyy.so,具体如下: System.loadLibrary("yyy");

System.loadLibrary("xxx");

本文结合使用实例进行说明。 创建jni目录.libs目录

在工程根目录下创建jni目录,libs目录不用手动建立,如图1所示。注意,这里使用的是ndk_R7,所以不需要用jdk去生成C文件。

图1

Java编写接口文件(Device.java)

Device.java的代码实现如下:

public class Device {

static {

System.loadLibrary("device");

}

public native String deviceTestString(String test);

}

方法名必须使用native关键字声明,并且必须使用system.loadLibrary("SO文件名")承载C类库。

编写C文件(devices.c)

这里编写的C代码属于Linux C范畴,实现代码如下:

#include <string.h>

#include <jni.h>

char* jstringTostrM(JNIEnv* env, jstring jstr)

{

char* pStr = NULL;

jclass jstrObj = (*env)->FindClass(env, "java/lang/String");

jstring encode = (*env)->NewStringUTF(env, "utf-8");

jmethodID methodId = (*env)->GetMethodID(env, jstrObj, "getBytes", "(Ljava/lang/String;)[B");

jbyteArray byteArray = (jbyteArray)(*env)->CallObjectMethod(env, jstr, methodId, encode);

jsize strLen = (*env)->GetArrayLength(env, byteArray);

jbyte *jBuf = (*env)->GetByteArrayElements(env, byteArray, JNI_FALSE); if (jBuf > 0)

{

pStr = (char*)malloc(strLen + 1);

if (!pStr)

{

return NULL;

}

memcpy(pStr, jBuf, strLen);

pStr[strLen] = 0;

}

(*env)->ReleaseByteArrayElements(env, byteArray, jBuf, 0);

return pStr;

}

jstring Java_com_jack_Device_deviceTestString(JNIEnv* env,jclass clazz,jstring path){

//system("echo devices.so test > /sdcard/log/log.txt");

char * test = jstringTostrM(env,path);

return (*env)->NewStringUTF(env, test);

}

注意C的函数命名规则,Java的jni标准必须有,com_jack_Device是Device.java文件的全名,再下来才是C函数名,jstringTostrM函数必须写在Java_com_jack_Device_deviceTestString函数前,如果不是,必须要在C文件头进行声明,声明代码为:

char* jstringTostrM(JNIEnv* env, jstring jstr);

编写Android.mk和编译android.mk

Android.mk的代码如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := device

LOCAL_SRC_FILES := device.c

include $(BUILD_SHARED_LIBRARY)

如果要编译成可执行文件,还需包含代码include $(BUILD_EXECUTABLE),之后按照图2所示编译即可。

图2

编写Java代码进行C函数调用

Device device = new Device();

String test = device.deviceTestString("你好~!!!");

Toast toast = Toast.makeText(Jack_ndk_jstringActivity.this, test, Toast.LENGTH_LONG); toast.setGravity(Gravity.TOP,0,150);

toast.show();

TextView text = (TextView) findViewById(R.id.text1);

text.setText(test);

注意,最后在AndroidManifest.xml文件中要加入文件控制权限,代码如下:

<!-- 文件权限 -->

<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

本文来源:https://www.bwwdw.com/article/m3z4.html

Top