android NDK JNI so文件的制作和使用

之前也接触过NDK和JNI,但是并没有很好的结合NDK和JNI来总结关于so文件的制作和使用。现在把最近一段时间的接触的关于so的制作和使用总结一下。
还是从最简单的例子开始:Android apk调用一个C函数,输出一个log记录,并返回一个字符串“Hello JNI”
##############################################################3
新建一个工程SoDemo

后面一直选择Next/Finish即可完成新建工程

修改activity_main.xml代码如下:
<?xml version=”1.0″ encoding=”utf-8″?>
<RelativeLayout xmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:tools=”http://schemas.android.com/tools”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:paddingBottom=”@dimen/activity_vertical_margin”
android:paddingLeft=”@dimen/activity_horizontal_margin”
android:paddingRight=”@dimen/activity_horizontal_margin”
android:paddingTop=”@dimen/activity_vertical_margin”
tools:context=”com.zj.sodemo.MainActivity”>
<TextView
android:id=”@+id/text”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:textAlignment=”center”
android:text=”Hello World!”
android:layout_alignParentTop=”true”
/>
<Button
android:id=”@+id/button”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:text=”click me”
android:layout_alignParentBottom=”true”
/>
</RelativeLayout>
功能介绍:加入一个文本框和按钮。apk运行后,点击按钮调用C程序,文本框显示返回的字符串
修改MainActivity.java代码如下:
package com.zj.sodemo;
import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
private Button mButton;
private TextView mTextView;
private String text = null;
static {
System.loadLibrary(“JNITest”);
}
public native String helloJNI();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton = (Button)findViewById(R.id.button);
mTextView = (TextView)findViewById(R.id.text);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
text = helloJNI();
mTextView.setText(text);
}
});
}
}
功能介绍:新建文本框和按钮,同时调用so库JNITest,调用so库里面的函数是helloJNI,同时为按钮建立一个点击监听器,点击按钮,则调用helloJNI()函数,并显示返回的字符串。
至此,前期准备工作都已完成
##########################################################3
接下来需要使用JDK工具javah来建立java和C/C++之间的联系
参考文档: android Studio & NDK: I got an error when “javah -d jni -classpath…” – http://stackoverflow.com/questions/27252712/android-studio-ndk-i-got-an-error-when-javah-d-jni-classpath
在  android ndk 入门 – 一个简单的ndk工程 : http://blog.csdn.net/u012005313/article/details/49911693 中,已经介绍了如何在android studio中配置javah
下面,我介绍一种使用命令行的方式
首先你需要先生成MainActivity.java的class文件,点击菜单栏build->Make Project(快捷键Ctrl + F9)即可编译整个工程。编译完成后,在路径app/build/intermediates/classes/debug/com/zj/sodemo下应该会出现MainActivity.class文件
android studio配置了控制台窗口,在窗口底部工具栏中应该有Terminal选项

如果不存在,则点击顶部菜单栏View->Tool Windows->Terminal(快捷键Ctrl + F12)就会弹出控制台窗口

进入main目录并新建文件夹jni

[plain] view plain copy

  1. cd app/src/main/
  2. mkdir jni


运行以下命令:
javah -d jni -classpath /opt/android-sdk-linux/platforms/android-24/android.jar:../../build/intermediates/classes/debug/ com.zj.sodemo.MainActivity
命令介绍:-d参数-输出目录
-classpath-从中加载类的路径。没有配置android.jar环境变量的话就需要在这里加入(注意,android.jar后面跟的是一个冒号:,而不是分号;
com.zj.sodemo.MainActivity是生成JNI样式的表头文件
在这里我们将生成的.h文件保存在jni文件夹内:

打开文件com_zj_sodemo_MainActivity.h:
/* DO NOT EDIT THIS FILE – it is machine generated */
#include <jni.h>
/* Header for class com_zj_sodemo_MainActivity */
#ifndef _Included_com_zj_sodemo_MainActivity
#define _Included_com_zj_sodemo_MainActivity
#ifdef __cplusplus
extern “C” {
#endif
#undef com_zj_sodemo_MainActivity_BIND_ABOVE_CLIENT
#define com_zj_sodemo_MainActivity_BIND_ABOVE_CLIENT 8L
#undef com_zj_sodemo_MainActivity_BIND_ADJUST_WITH_ACTIVITY
#define com_zj_sodemo_MainActivity_BIND_ADJUST_WITH_ACTIVITY 128L
#undef com_zj_sodemo_MainActivity_BIND_ALLOW_OOM_MANAGEMENT
#define com_zj_sodemo_MainActivity_BIND_ALLOW_OOM_MANAGEMENT 16L
#undef com_zj_sodemo_MainActivity_BIND_AUTO_CREATE
#define com_zj_sodemo_MainActivity_BIND_AUTO_CREATE 1L
#undef com_zj_sodemo_MainActivity_BIND_DEBUG_UNBIND
#define com_zj_sodemo_MainActivity_BIND_DEBUG_UNBIND 2L
#undef com_zj_sodemo_MainActivity_BIND_EXTERNAL_SERVICE
#define com_zj_sodemo_MainActivity_BIND_EXTERNAL_SERVICE -2147483648L
#undef com_zj_sodemo_MainActivity_BIND_IMPORTANT
#define com_zj_sodemo_MainActivity_BIND_IMPORTANT 64L
#undef com_zj_sodemo_MainActivity_BIND_NOT_FOREGROUND
#define com_zj_sodemo_MainActivity_BIND_NOT_FOREGROUND 4L
#undef com_zj_sodemo_MainActivity_BIND_WAIVE_PRIORITY
#define com_zj_sodemo_MainActivity_BIND_WAIVE_PRIORITY 32L
#undef com_zj_sodemo_MainActivity_CONTEXT_IGNORE_SECURITY
#define com_zj_sodemo_MainActivity_CONTEXT_IGNORE_SECURITY 2L
#undef com_zj_sodemo_MainActivity_CONTEXT_INCLUDE_CODE
#define com_zj_sodemo_MainActivity_CONTEXT_INCLUDE_CODE 1L
#undef com_zj_sodemo_MainActivity_CONTEXT_RESTRICTED
#define com_zj_sodemo_MainActivity_CONTEXT_RESTRICTED 4L
#undef com_zj_sodemo_MainActivity_MODE_APPEND
#define com_zj_sodemo_MainActivity_MODE_APPEND 32768L
#undef com_zj_sodemo_MainActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING
#define com_zj_sodemo_MainActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING 8L
#undef com_zj_sodemo_MainActivity_MODE_MULTI_PROCESS
#define com_zj_sodemo_MainActivity_MODE_MULTI_PROCESS 4L
#undef com_zj_sodemo_MainActivity_MODE_NO_LOCALIZED_COLLATORS
#define com_zj_sodemo_MainActivity_MODE_NO_LOCALIZED_COLLATORS 16L
#undef com_zj_sodemo_MainActivity_MODE_PRIVATE
#define com_zj_sodemo_MainActivity_MODE_PRIVATE 0L
#undef com_zj_sodemo_MainActivity_MODE_WORLD_READABLE
#define com_zj_sodemo_MainActivity_MODE_WORLD_READABLE 1L
#undef com_zj_sodemo_MainActivity_MODE_WORLD_WRITEABLE
#define com_zj_sodemo_MainActivity_MODE_WORLD_WRITEABLE 2L
#undef com_zj_sodemo_MainActivity_DEFAULT_KEYS_DIALER
#define com_zj_sodemo_MainActivity_DEFAULT_KEYS_DIALER 1L
#undef com_zj_sodemo_MainActivity_DEFAULT_KEYS_DISABLE
#define com_zj_sodemo_MainActivity_DEFAULT_KEYS_DISABLE 0L
#undef com_zj_sodemo_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL
#define com_zj_sodemo_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L
#undef com_zj_sodemo_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL
#define com_zj_sodemo_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L
#undef com_zj_sodemo_MainActivity_DEFAULT_KEYS_SHORTCUT
#define com_zj_sodemo_MainActivity_DEFAULT_KEYS_SHORTCUT 2L
#undef com_zj_sodemo_MainActivity_RESULT_CANCELED
#define com_zj_sodemo_MainActivity_RESULT_CANCELED 0L
#undef com_zj_sodemo_MainActivity_RESULT_FIRST_USER
#define com_zj_sodemo_MainActivity_RESULT_FIRST_USER 1L
#undef com_zj_sodemo_MainActivity_RESULT_OK
#define com_zj_sodemo_MainActivity_RESULT_OK -1L
/*
* Class: com_zj_sodemo_MainActivity
* Method: helloJNI
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_zj_sodemo_MainActivity_helloJNI
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
里面有函数声明JNIEXPORT jstring JNICALL Java_com_zj_sodemo_MainActivity_helloJNI
接下来就是实现该函数声明
#############################################3
生成.h文件后我们就可以编写相应的C/C++实现代码
在jni目录下新建main.cpp,代码如下:
#include <iostream>
#include <jni.h>
#include <android/log.h>
#include “com_zj_sodemo_MainActivity.h”
using namespace std;
#define LOG_TAG “zj”
#define LOGI(…) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
extern “C”
{
/*
* Class: com_zj_sodemo_MainActivity
* Method: helloJNI
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_zj_sodemo_MainActivity_helloJNI
(JNIEnv *env, jobject obj)
{
LOGI(“now in jni world”);
return env->NewStringUTF(“Hello JNI”);
}
}
程序介绍:
1.生成so文件需要头文件jni.h;
2.输出log需要头文件android/log.h;
3.需要包含头文件com_zj_sodemo_MainActivity.h并实现其中声明的函数
4.如果使用C++代码,则必须实现本地方法的声明extern “C”(阻止C++编译器生产C++特有的代码)
5.JNICALL Java_com_zj_sodemo_MainActivity_helloJNI定义中实现了一条记录的输出,并返回一个字符串
#################################################
参考:
android studio 使用 jni 编译 OpenCV 完整实例 之 图像边缘检测!从此在andrid中自由使用 图像匹配、识别、检测 – http://www.cnblogs.com/linguanh/p/4624768.html?utm_source=tuicool&utm_medium=referral
android ndk 入门之打印log信息 – http://blog.csdn.net/qiuxiaolong007/article/details/7548580
接下来就是生成so库
在目录jni中新建Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := JNITest
LOCAL_SRC_FILES := main.cpp
LOCAL_LDLIBS +=-L$(SYSROOT)/usr/lib -lm -llog
include $(BUILD_SHARED_LIBRARY)
新建Application.mk:
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi-v7a #这句是设置生成的cpu指令类型,提示,目前绝大部分安卓手机支持armeabi,libs下太多类型,编译进去 apk 包会过大
APP_PLATFORM := android-8 #这句是设置最低安卓平台,可以不弄
打开android stdio的控制台窗口,进入jni路径,运行命令ndk-build:

运行成功,同时生成so库libJNITest.so,位于目录libs/armeabi-v7a中:

###############################
有两种方式使用so库。
1.android studio默认调用src/main/jniLibs下的so文件;
2.通过配置,可以使用src/main/libs下的so文件
我们现在实现第2种。打开app/build.gradle文件,在android{}内加入:
sourceSets {
main() {
jniLibs.srcDirs = [‘src/main/libs’]
jni.srcDirs = []
}
}
同时,在gradle.properties文件中加入语句:
android.useDeprecatedNdk=true
编译整个工程:点击顶部菜单栏Build->Make Project
编译完成后点击运行按钮(Run ‘app’,快捷键Shift + F10)

点击按钮

下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/3085,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?