Android studio 下JNI编程实例并生成so库的实现代码

最近需要使用JNI编程,学了下JNI,并且在Android Studio下实现了一个小demo。这期间有一些坑,还好都解决了,想分享出来,希望大家少走弯路。本文中采用的平台是Windows,NDK环境已经搭建好,这方面资料很多,大家可以自行百度。

本文分为两个部分:

1.如何通过编写Jni实现native方法的调用。

2.怎样生成.so动态库提供给第三方使用。

以下是正文:

一,编写jni文件,实现本地方法

1,建立一个新工程,只有一个MainActivity,里面加载库文件并且调用若干本地方法,然后通过Android Studio里的build-makeProject生成class文件。

public class MainActivity extends Activity {
  private final String TAG = "JNITEST"

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    String s=returnString();
    Log.d(TAG,s);
    int a=1000;
    Log.d(TAG,sayhello(a));
  }
  //加载jni
  static {
    System.loadLibrary("nativeTest");
  }
  //声明native方法
  private native int sayhello(int t);
  private native String returnString();

}

2,生成.h头文件,里面有Android工程里本地方法的声明。这个文件可以自己写,但是推荐用javah自动生成。生成方法为:在控制台或者Android studio自带的控制台使用javah命令将上一步make之后生成的class文件生成.h头文件,这里在用javah的时候有可能会出问题,比如我第一次就出现了找不到app.activity ,即找不到类文件,这种问题一般是没有理解javah的用法造成的。我当时采用以下两种方法:

方法1: cd到 E:\shijue\JniHello\app\src\main

然后输入 javah -d jni -classpath I:\Andriod\AndroidSDK\platforms\android-15\android.jar;
E:\shijue\JniHello\app\build\intermediates\classes\debug com.example.machenike_pc.jnihello.MainActivity

说明:javah是生成头文件的命令,深绿色为生成文件夹jni,紫红色为android.jar所在的位置,浅绿色为class文件的路径+类全名(路径最后一个文件夹是debug之后空格+类全名)

(这里补充下-classpath的含义:javah操作是针对类文件,-bootclasspath和-classpath就是指定在哪里进行类文件搜索。JDK搜索类文件先后顺序如下:Bootstrap classes,User classes。Bootstrap默认的是JDK自带的jar或zip文件,它包括jre\lib下rt.jar等文件,JDK首先搜索这些文件.可以通过-bootclasspath来设置它。文件之间用分号";"进行分割。User classes搜索顺序为当前目录、环境变量 CLASSPATH、-classpath。它们用于告知JDK搜索类文件根目录名、jar文档名、zip文档名,用分号";"进行分隔。)

方法2: cd到E:\shijue\JniHello\app\build\intermediates\classes\debug目录下,直接javah -d jni com.example.machnike_pc.jnihello.MainActivity 即可

3,在生成的jni目录下写一个c或者c++文件,文件名随意,实现本地方法 ,之后需要在该路径下再加一个空的cpp或c文件(估计是软件的bug,不加的话很可能出ndk错误),比如我加了个util.cpp的文件,里面什么都不写。

下面是我的c++代码

#include<jni.h>
#include<stdio.h>
#include<com_example_machenike_pc_jnitest2_MainActivity.h>

#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jint JNICALL Java_com_example_machenike_1pc_jnitest2_MainActivity_sayhello
 (JNIEnv *, jobject, jint);

JNIEXPORT jstring JNICALL Java_com_example_machenike_1pc_jnitest2_MainActivity_returnString
 (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif

JNIEXPORT jint JNICALL Java_com_example_machenike_1pc_jnitest2_MainActivity_sayhello
  (JNIEnv * env, jobject jobj, jint jnumber)
  {
    int modify=jnumber+1;
    return modify;

  }
JNIEXPORT jstring JNICALL Java_com_example_machenike_1pc_jnitest2_MainActivity_returnString
  (JNIEnv *env, jobject jobj)
  {
    return env->NewStringUTF("I'm comes from to Native Function!");
   }

4,如果ndk版本不是最新的,需要在gradle.properties文件下加入:

android.useDeprecatedNdk=true

5,配置ndk路径,这里也可以在AS的设置里面配置。我采用的方法是在local.properties文件最后一行加入:

ndk.dir=I\:\\Andriod\\NDK\\android-ndk-r10b

6,build.gradle(app下):文件下加入:(defaultconfig里面)

ndk{
moduleName "nativeTest"
}

此时运行程序已经可以实现本地方法了,之后可以再生成so库文件,方便使用。

二,生成.so动态库

(这里说一下,貌似Android studio已经写好了.mk文件,上面的步骤完成后,直接rebuild一下就自动生成为了.so动态库,下面的方法也能生成,可以看一下,很有用)

1,在jni文件夹下新建Android.mk文件,写入以下内容:

LOCAL_PATH := $(call my-dir)           //固定写法,把路径赋给LOCAL_PATH变量
include $(CLEAR_VARS)                  //清除其他LOCAL变量
LOCAL_MODULE := nativeTest             //这个模块的名字,最后生成的.so的名字就是它,要跟java里面的loadLibray的名字一样。
LOCAL_SRC_FILES := nativeTest.cpp\     //这里是要编译的文件,\ 符号是换行
            util.cpp
include $(BUILD_SHARED_LIBRARY)        //SHARED_LIBRARY就是动态库,即.so文件

这里的写法是最简单的一个例子,用的时候把注释去掉。每一行都是很关键,不能省略。至于makefile怎么编写内容比较多,此处不赘述。

2,在工程根目录下新建application.make文件,写入以下内容:

APP_PROJECT_PATH := $(call my-dir)
APP_MODULES := nativeTest
3,在命令行下,cd到jni目录(就是之前javah -d jni生成的那个文件夹)下,输入指令: ndk-build,等一会即可生成.so文件。位于lib目录下,将其放到app/src/main/jniLibs目录下就能用了。

FAQ:

1,生成的so文件在使用时需要注意:包名不能变,拿上文举例,本地方法位于com_example_machenike_pc_jnitest2_MainActivity这个类下,如果在别的地方用,需要完整的建立这个包名和类。
2,c和cpp文件均可以用来写jni,写法上略有不同。
3,需要注意java里面成员方法和静态方法通过javah生成的头文件略有不同,一个参数是jclass,另一个是jobject。
4,不用javah生成头文件也行,推荐第一次写的时候用javah生成,后面修改的时候(比如参数改变)可以直接在c文件里手动修改。

补充:

SourcePath: D:\work\androidstudio\VisualRecognition\app\src\main\java (绝对路径)

TargetPath: D:\work\androidstudio\VisualRecognition\visual\src\main\jni (绝对路径)

TargetClassName: com.yf.visualrecognition.UnityPlayerActivity (你的包名+类名)

格式: javah -d ${SourceFile} -classpath ${TargetPath} ${TargetClassName}

生成.h文件:javah -d E:\AndroidProject\GitHubProject\OpenCV\OpenCV\app\src\main\jni -classpath E:\AndroidProject\GitHubProject\OpenCV\OpenCV\app\src\main\java com.cosco.opencv.OpenCVHelper

(0)

相关推荐

  • Android Studio打包.so库到apk中实例详解

    Android Studio打包.so库到apk中实例详解 由于在原来的ADT的Eclipse环境中,用ndk_build工具生成了相应的各个.so库文件之后,eclipse工具就会自动把这些库导入到apk中.而Android Studio目前为止(1.1.0版本)还无法做到那么自动,但是我们可以通过以下方式进行. 首先在Android Studio工程的app目录下创建整个jni目录,jni目录里写Android.mk.Application.mk以及各类C/C++和汇编源文件.然后跟原来一样

  • 详解Android Studio如何导入第三方类库、jar包和so库

    第三方类库源码 将一网友的XMPP代码从ADT转到AS时,发现其使用了第三方类库,源码放在了lib下,直接在AS中Import project,第三方类库并没有自动导入进来,看来需要自己动手了. 项目的目录结构如下: XMPP$ ls app build.gradle gradlew import-summary.txt XMPP.iml build gradle gradlew.bat local.properties settings.gradle 将第三方源码qqEmoji-lib拷到此目

  • 浅谈Android Studio JNI生成so库

    1.新建Android studio工程 2.新建class:AppKey.java.主要为了保存密钥 代码块 package com...adminapp.lib.utils.jni; /** * Created by seven on 16/9/8. */ public class AppKey { static { System.loadLibrary("AppKey"); } public static native String WechatId(); public stat

  • Android Studio中导入JNI生成的.so库的实现方法

    Android Studio中导入JNI生成的.so库的实现方法 由于在原来的ADT的Eclipse环境中,用ndk_build工具生成了相应的各个.so库文件之后,eclipse工具就会自动把这些库导入到apk中.而Android Studio目前为止(0.86版本)还无法做到那么自动,但是我们可以通过以下方式进行. 首先在Android Studio工程的app目录下创建整个jni目录,jni目录里写Android.mk.Application.mk以及各类C/C++和汇编源文件.然后跟原来

  • Android studio so库找不到问题解决办法

    Android studio so库找不到问题解决办法 问题: java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[ zip file "/data/app/com.bb.aaaa.nfcandimg-1/base.apk", zip file "/data/app/com.bb.aaaa.nfcandimg-1/split_lib_dependencies_apk.apk&qu

  • Android studio 下JNI编程实例并生成so库的实现代码

    最近需要使用JNI编程,学了下JNI,并且在Android Studio下实现了一个小demo.这期间有一些坑,还好都解决了,想分享出来,希望大家少走弯路.本文中采用的平台是Windows,NDK环境已经搭建好,这方面资料很多,大家可以自行百度. 本文分为两个部分: 1.如何通过编写Jni实现native方法的调用. 2.怎样生成.so动态库提供给第三方使用. 以下是正文: 一,编写jni文件,实现本地方法 1,建立一个新工程,只有一个MainActivity,里面加载库文件并且调用若干本地方法

  • 如何在Android Studio下进行NDK开发

    在AS中进行NDK开发之前,我们先来简单的介绍几个大家都容易搞懵的概念: 1. 到底什么是JNI,什么是NDK? 2. 何为"交叉编译"? 先看什么是JNI?JNI的全称就是Java Native Interface,即java本地开发接口.可能大家和我一样,一听到接口什么的就犯懵:"我也知道这是java本地开发接口的意思,但它具体是个什么意思我还是搞不明白."其实JNI它就是一种协议,一说协议,那它就是对某种东西的一个规范和约束,说的好听一点就是标准化.如果你想用

  • Android Studio 下 Flutter 开发环境搭建,Flutter,Dart 插件安装,Flutter SDK 安装,环境变量配置,开发环境检查

    I . Flutter 学习资料 Flutter 学习资料 : ① 官方文档 : https://flutter.dev/docs ② Flutter Android 开发者文档 : https://flutter.dev/docs/get-started/flutter-for/android-devs ② Flutter 插件库 : https://pub.dev/ II . Flutter 开发环境搭建 Flutter 开发环境搭建 : ① Android Studio : https:/

  • Android Studio下的APP目录结构详解

    Project Name:工程项目名称 Application Name:当前应用发布以后的名字,例如QQ图标下面的名字是"QQ",就是Application Name. Android Studio工程目录 1..gradle和.idea 这两个目录下放置的都是Android Studio自动生成的一些文件,我们无须关心,也不要去手动编辑. 2.app 项目中的代码.资源等内容几乎都是放置在这个目录下的,我们后面的开发工作也基本都是在这个目录下进行的,待会儿还会对这个目录单独展开进行

  • Android studio 下的APK打包失败问题解决办法

    Android studio 下的APK打包失败问题解决办法 今天遇到了一个奇怪的问题,本来在Android studio 1.4上运行的好好的程序,到了我更新完的Android studio 2.1上就打包失败了,但是用调试机直接运行则没问题. 最后在app下的build.gradle下加入了这样的一段代码就通过了: lintOptions { abortOnError false checkReleaseBuilds false // 防止在发布的时候出现因MissingTranslatio

  • Android Studio下添加assets目录的实现方法

    有时候需要放置一些文件而且不被proguard压缩,可以放到assets目录中. 但是工程默认并未创建assets目录,那么如何在android studio中创建assets目录呢? 目录位置为:XXX\src\main\assets XXX代表你的项目的路径,assets放在src\main目录下. 以上这篇Android Studio下添加assets目录的实现方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • Android Studio获取SHA1值实例详解

    Android Studio获取SHA1值实例详解 前言 使用百度地图的小伙伴们都会知道获取百度地图的密钥需要SHA1和包名,在Eclipse中,我们可以很方便的得知SHA1值,如下图: 但是在Android Studio中,该怎么获取SHA1的值呢?不要着急,马上呈上~ Android Studio获取SHA1值 强大的Android Studio为我们提供了Terminal这个工具,我们可以通过他进行相应命令从而获取所需内容. Java中提供了Keytool工具去让我们管理证书,那么接下来我

  • Android自定义控件下拉刷新实例代码

    实现效果: 图片素材: --> 首先, 写先下拉刷新时的刷新布局 pull_to_refresh.xml: <resources> <string name="app_name">PullToRefreshTest</string> <string name="pull_to_refresh">下拉可以刷新</string> <string name="release_to_refre

  • Android Studio 下自动注释(自定义作者,类作用等)图文详解

    Eclipse 的自动注释相信大家都不会陌生,http://www.jb51.net/article/105094.htm,来到Android Studio之后我们会发现这个有用的功能竟然没有!(其实是被Android Studio隐藏了),鼓捣一番也就那么回事-.- 很简单,首先打开你的Android Studio  在工具栏点击如图小图标 然后在进入页面里搜索:File and Code Templates,如图 再如图 新建一个类试试 总结 以上所述是小编给大家介绍的Android Stu

  • Android Studio 中获取屏幕宽度实例

    获取整个屏幕的宽度的实例 Point p = new Point(); //获取窗口管理器 WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); wm.getDefaultDisplay().getSize(p); screenWidth = p.x; // 屏幕宽度 补充知识:Android屏幕适配之动态设置单个控件的宽高比例 前言:这个问题出现在我做平板项目的时候,需要横排显示

随机推荐