1. androidStudio如何配置NDK/JNIAndroidStudio怎么调用so动态链接库
AndroidStudio怎么调用so动态链接库?在我们日常开发中,经常会用到一些复杂的加密的算法以保证通信的安全。通常这些算法会用C或C++实现后打包成.so动态链接库并向java层开发接口方便调用。
以AndroidStudio为例
1 . 首先去下载NDK包,下载路径如下可根据自己系统定点下载
https://developer.android.google.cn/ndk/downloads/index.html
static{
System.loadLibrary("jnitext");
}
publicnativeStringget_1111CLang_1String();
2. AndroidStudio怎样使用NDK开发示例
1、新建一个Android工程,这一步就不多说了;
2、在AndroidStudio中配置NDK路径,方法是:
(1)先下载NDK并安装(这句基本是废话);
(2)点菜单栏的File->ProjectStructure…->在打开的窗口中左侧选中SDKLocation->在右侧Android NDK Location中填入NDK目录所在路径
3、编译生成.class文件,方法是:
点菜单栏的Build->Make Project
这时,在工程的app/build/intermediates下就会生成classes文件夹,打开classes目录下的debug目录就会看到以你的包名命名的各级文件夹,最里边文件夹下有你的Java类对应的.class文件;
4、确定你要引用本地方法的类:
其实你也可以先生成jni目录,再去创建这个类,但是先Google显然建议先创建要引用C代码的Java类,因为AndroidStudio可以根据你在java类中定义的native方法的名称来自动生成.h头文件。
比如你想在MainActivity中引用本地方法,那么你先用
static {
System.loadLibrary("myNativeLib");
}
来声明本地代码库,然后定义几个natvie方法,比如
public native String getStringFromNative();
5、使用javah命令行生成jni目录及对应的头文件:
我用的是AndroidStudio 2.1.1,在主界面最下边就能找到Terminal,点一下就能打开系统的命令行工具,并且已经为你自动cd到当前工程所在目录
6、配置build.gradle文件
这里的build.gradle是指app模块下的build.gradle,不是整个工程的build.gradle文件。在模块的build.gradle的defaultConfig下加入以下idk配置:
ndk {
moleName"myNativeLib"
ldLibs "log", "z", "m"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
7、配置local.properties文件
打开工程目录下的local.properties,感觉这一步是自动配置的,或者说在你一开始在AndroidStudio中指定NDK目录时已经自动生成了。我的AndroidStudio在打开local.properties已经有了
ndk.dir=/Develop/Android/android-ndk-r10e
这一行,所以就不用配了;
8、配置gradle.properties
打开工程目录下的gradle.properties文件(注意不是build.gradle,而是gradle.properties),在文件的最后一行加入
android.useDeprecatedNdk=true
这句的作用是允许我们使用已经过时的NDK版本,不知道AndroidStudio要求使用哪个版本的NDK才不会报错,总之只要配置了这一句就可以使用比较旧的NDK版本了,我用的r10;
至此我们在AndroidStudio中就完成了NDK环境的配置,接下来就可以写Native代码了;
9、写一个.c文件测试一下是否运行正常
(1)在我们之前生成src/main/jni目录下新建一个.c文件,方法是在jni文件夹上点鼠标右键,选择New->C/C++ Source File,然后在弹出的对话框中填入.c或.cpp文件的文件名就可以了,比如说mail.c
3. Android Studio怎么用JNI编写出Hello World
第一步:
在自己项目中创建一个包含native的方法类HelloWorld.java -->包名com.ningso.ningsodemo
public class HelloWorld {
public native String sayHello(String name); // 1.声明这是一个native函数,由本地代码实现
static {
System.loadLibrary("hello"); // 2.加载实现了native函数的动态库,只需要写动态库的名字
}
}
第二步:
在终端执行javac命令将.java源文件编译成.class字节码文件
完结
4. 为什么在android studio里javah命令不存在,但是在cmd里没错
进入Java目录执行如下命令
javah -d ../jni packageName.className
例如:
javah -d ../jni com.dremap.okhttpdemo.NdkJniUtils
5. android jni abifilters为什么没产生文件
android studio 中简单的jni开发
Let’s Go!!!
准备工作不再需要什么cgwin来编译ndk(太特么操蛋了),现在只需要你下载一下NDK的库就ok了,然后你也可以去离线下载http://www.androiddevtools.cn最新版,这里吐槽一下android studio对NDK的支持还有待提高。
效果
看下今天的效果:(安卓jni获取 apk的包名及签名信息)
必须的步骤
1.配置你的ndk路径(local.properties)
ndk.dir=E:\Android\sdk\android-ndk-r11b-windows-x86_64\android-ndk-r11b
2.grale配置使用ndk(gradle.properties)
android.useDeprecatedNdk=true
3.在mole下的build.gradle添加ndk以及jni生成目录
ndk{
moleName “JNI_ANDROID”
abiFilters “armeabi”, “armeabi-v7a”, “x86” //输出指定三种abi体系结构下的so库,目前可有可无。
}
sourceSets.main{
jniLibs.srcDirs = [‘libs’]
}
准备工作做好了开始写代码:(jni实现获取应用的包名和签名信息)
步骤1:先写要实现本地方法的类,及加载库(JNI_ANDROID也就是ndk 里面配的moleName)
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<code class="hljs java">package com.losileeya.getapkinfo;
/**
* User: Losileeya ([email protected])
* Date: 2016-07-16
* Time: 11:09
* 类描述:
*
* @version :
*/
public class JNIUtils {
/**
* 获取应用的签名
* @param o
* @return
*/
public static native String getSignature(Object o);
/**
* 获取应用的包名
* @param o
* @return
*/
public static native String getPackname(Object o);
/**
* 加载so库或jni库
*/
static {
System.loadLibrary("JNI_ANDROID");
}
}</code>
注意我们 的加载c方法都加了native关键字,然后要使用jni下的c/c++文件就必须使用System.loadLibrary()。
步骤2:使用javah命令生成.h(头文件)
javah -jni com.losileeya.getapkinfo.JNIUtils
执行完之后你可以在mole下文件夹app\build\intermediates\classes\debug下看见生成的 .h头文件为:
com_losileeya_getapkinfo_JNIUtils.h
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<code class="hljs vala">/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_losileeya_getapkinfo_JNIUtils */
#ifndef _Included_com_losileeya_getapkinfo_JNIUtils
#define _Included_com_losileeya_getapkinfo_JNIUtils
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jstring JNICALL Java_com_losileeya_getapkinfo_JNIUtils_getPackname(JNIEnv *, jobject, jobject);
JNIEXPORT jstring JNICALL Java_com_losileeya_getapkinfo_JNIUtils_getSignature(JNIEnv *, jobject, jobject);
#ifdef __cplusplus
}
#endif
#endif</jni.h></code>
在工程的main目录下新建一个名字为jni的目录,然后将刚才的.h文件剪切过来,当然文件名字是可以修改的
步骤3:根据.h文件生成相应的c/cpp文件
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<code class="hljs scala">//
// Created by Administrator on 2016/7/16.
//
#include <stdio.h>
#include <jni.h>
#include <stdlib.h>
#include "appinfo.h"
JNIEXPORT jstring JNICALL Java_com_losileeya_getapkinfo_JNIUtils_getPackname(JNIEnv *env, jobject clazz, jobject obj)
{
jclass native_class = env->GetObjectClass(obj);
jmethodID mId = env->GetMethodID(native_class, "getPackageName", "()Ljava/lang/String;");
jstring packName = static_cast<jstring>(env->CallObjectMethod(obj, mId));
return packName;
}
JNIEXPORT jstring JNICALL Java_com_losileeya_getapkinfo_JNIUtils_getSignature(JNIEnv *env, jobject clazz, jobject obj)
{
jclass native_class = env->GetObjectClass(obj);
jmethodID pm_id = env->GetMethodID(native_class, "getPackageManager", "()Landroid/content/pm/PackageManager;");
jobject pm_obj = env->CallObjectMethod(obj, pm_id);
jclass pm_clazz = env->GetObjectClass(pm_obj);
// 得到 getPackageInfo 方法的 ID
jmethodID package_info_id = env->GetMethodID(pm_clazz, "getPackageInfo","(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
jstring pkg_str = Java_com_losileeya_getapkinfo_JNIUtils_getPackname(env, clazz, obj);
// 获得应用包的信息
jobject pi_obj = env->CallObjectMethod(pm_obj, package_info_id, pkg_str, 64);
// 获得 PackageInfo 类
jclass pi_clazz = env->GetObjectClass(pi_obj);
// 获得签名数组属性的 ID
jfieldID signatures_fieldId = env->GetFieldID(pi_clazz, "signatures", "[Landroid/content/pm/Signature;");
jobject signatures_obj = env->GetObjectField(pi_obj, signatures_fieldId);
jobjectArray signaturesArray = (jobjectArray)signatures_obj;
jsize size = env->GetArrayLength(signaturesArray);
jobject signature_obj = env->GetObjectArrayElement(signaturesArray, 0);
jclass signature_clazz = env->GetObjectClass(signature_obj);
jmethodID string_id = env->GetMethodID(signature_clazz, "toCharsString", "()Ljava/lang/String;");
jstring str = static_cast<jstring>(env->CallObjectMethod(signature_obj, string_id));
char *c_msg = (char*)env->GetStringUTFChars(str,0);
return str;
}</jstring></jstring></stdlib.h></jni.h></stdio.h></code>
注意:要使用前得先声明,方法名直接从h文件考过来就好了,studio目前还是很操蛋的,对于jni的支持还是不很好。
步骤4:给项目添加Android.mk和Application.mk
此步骤显然也是不必要的,如果你需要生成so库添加一下也好,为什么不呢考过去改一下就好了,如果你不写这2文件也是没有问题的,因为debug下也是有这些so库的。
好吧,勉强看一下这2货:
Android.mk
?
1
2
3
4
5
<code class="hljs ruby">LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := JNI_ANDROID
LOCAL_SRC_FILES =: appinfo.cpp
include $(BUILD_SHARED_LIBRARY)</code>
Application.mk
?
1
2
<code class="hljs makefile">APP_MODULES := JNI_ANDROID
APP_ABI := all</code>
android studio下External Tools的高级配置NDK一键javah,ndk生成so库
eclipse开发ndk的时候你可能就配置过javah,所以android studio也可以配置,是不是很兴奋:
Settings—>Tools—->External Tools就可以配置我们的终端命令了,别急一个一个来:
javah -jni 命令的配置(一键生成h文件)
我们先来看参数的配置:
1.Program:JDKPath\bin\javah.exe 这里配置的是javah.exe的路径(基本一致)
2.Parametes: -classpath . -jni -d MoleFileDir/src/main/jni FileClass这里指的是定位在Mole的jni文件你指定的文件执行jni指令<㖞�"/kf/ware/vc/" target="_blank" class="keylink">++IpDQo8cD48aW1nIGFsdD0="" src="/uploadfile/Collfiles/20160718/201607181017581505.png" title="\" />
我们同样来看参数的配置:
1.Program:E:\Android\sdk\android-ndk-r11b-windows-x86_64\android-ndk-r11b\ndk-build.cmd 这里配置的是ndk下的ndk-build.cmd的路径(自己去找下)
2.Working:MoleFileDir\src\main\
javap-s(此命令用于c掉java方法时方法的签名)
我们同样来看参数的配置:
1.Program:JDKPath\bin\javap.exe 这里配置的是javap.exe的路径(基本一致)
2.Parametes: -classpathMoleFileDir/build/intermediates/classes/debug -s FileClass 这里指的是定位到build的debug目录下执行 javap -s class文件
3.Working:MoleFileDir
这里介绍最常用的3个命令,对你的帮助应该还是很大的来看一下怎么使用:
javah -jni的使用:选中native文件—>右键—>External Tools—>javah -jni
效果如下:
是不是自动生成了包名.类名的.h文件。
ndk-build的使用:选中jni文件—>右键—>External Tools—>ndk-build
效果如下:
是不是一键生成了7种so库,你还想去debug目录下面去找吗
javap-s的使用:选中native文件—>右键—>External Tools—>javap-s
效果如下:
看见了每个方法下的descriptor属性的值就是你所要的方法签名。
3种一键生成的命令讲完了,以后你用到了什么命令都可以这样设置,是不是很给力。
6. android studio 2.0 include lt;jni.h>找不到 有知道的小伙伴吗
总共有三种方式生成Jni头文件,但归根结底只有一种,只是操作方法不一样,我在这里做一下记录,方便下次使用。1.11.利用AndroidStudio的Terminal,进入你自己的Android工程文件的app/src/main目录,例如(D:\Users\AndroidStudio\Application\app\src\main)在Terminal中输入命令cdapp\src\main这样就进入到了main目录,可以使用dir命令查看当前目录有哪些文件总共有三种方式生成Jni头文件2.在Terminal中输入命令javah-djni-jni-classpath..\..\build\intermediates\classes\debugcom.example.lenovo.application.JniClass解释:-d输出目录,后面跟上要生成的目录名-jni生成Jni样式的标头文件-classpath指定加载类的路径,后面跟上你要生成头文件的这个类的路径,例如:..\..\..\build\intermediates\classes\debug(这个是类所在的路径)com.example.lenovo.application.JniClass(类的包名)注意,要生成.class文件,要MakeProject3.如果前面没有出错的话,就能看到jni文件和生成的头文件其实jni目录可以不用命令生成,AndroidStudio已经为我们准备好了。这样就能快速的生成jni目录了。然后在Terminal中进入到该目录,输入命令cdapp\src\main\jni在执行如下命令javah-djni-jni-classpath..\..\build\intermediates\classes\debugcom.example.lenovo.application.JniClass这样也能生成头文件利用Windows的cmd生成jni头文件1.进入到你自己Android工程目录下的app\build\intermediates\classes\debug2.然后Shift加鼠标右键,点击红色方框的内容3.出现cmd命令行,输入如下命令javah-jnicom.example.lenovo.application.JniClass4.会在当前目录生成*.h头文件,把它拷贝进jni目录就可以了。jni目录可以按照上面的方法创建至此,生成jni头文件的三种方法讲解完毕。
7. android studio JNI开发时 编译成功 但是没有生成.so文件 什么原因
1 在交叉编译的时候怎么都无法生成so文件,javah生成头文件没错,c文件也没错,java文件也没错,
2.原因:是JNI文件夹路径不对
3 在执行javah命令时,我进入的是cd app/src/main/java 这样jni文件夹在java文件夹下,作为一个包存在,这样就无法生成so文件
执行javah的正确姿势:
4 进入app/src/main目录:cd app/src/main
执行javah命令:javah
javah -d jni -classpath ./Java lab.sodino.jnitest.MainActivity
5, -d jni 头文件生成到jni文件夹(当前在<Project>\app\src\main目录下,所以.h所在的目录为<Project>\app\src\main\jni )
-classpath ./java 指定去当前路径下java下寻找包名指定的类
这样再rebuild一下,就会生成so文件了
8. 如何给android工程添加ndk
建立项目,并设置activity.xml布局文件,这一点与普通编程没有不同。通过一个简单的文本展示实验。在MainActivity中添加native接口,并加载.so库生成项目的.class文件。首先选中项目后,在菜单栏选择Build-->MakeProject。Make之后,将生成.class文件,生成的.class文件位于app_path/build/intermediates/classes/debug/包名利用javah生成C头文件:点击"View->ToolWindows->Terminal",即在Studio中进行终端命令行工具。在控制台中通过命令“cdapp\src\main\java”,进入到java目录下。操作指令:javah-d../jnivrlab.ndkdemoforandroidstudio.MainActivity。此时在main目录下生成一个jni文件夹,其中在jni文件夹中有生成的.h头文件。编辑C文件,在jni文件夹下新建文件命名为main.c。并在该文件中导入需要的头文件,实现上一步生成的头文件中的方法。配置NDK路径,在local.properties中指明sdk和ndk路径:设置ndk参数,名字、发布平台等。在应用目录下的build.gradle中defaultConfig中设置生成.so文件,此时再次选择Build-->BuildProject就可以生成so文件了。出现不支持NDK的错误提示,不过跟着错误提示修改:在项目空间下的gradle.properties中添加android.useDeprecatedNdk=true。针对三种不同的CPU生成了三种不同的.so文件。生成的.so文件位于app_path/build/intermediates/ndk/debug/lib.安装运行~~去吧,皮卡丘
9. android studio JNI开发时 编译成功 但是没有生成.so文件 什么原因
1
在交叉编译的时候怎么都无法生成so文件,javah生成头文件没错,c文件也没错,java文件也没错,
2.原因:是JNI文件夹路径不对
3
在执行javah命令时,我进入的是cd
app/src/main/java
这样jni文件夹在java文件夹下,作为一个包存在,这样就无法生成so文件
执行javah的正确姿势:
4
进入app/src/main目录:cd
app/src/main
执行javah命令:javah
javah
-d
jni
-classpath
./Java
lab.sodino.jnitest.MainActivity
5,
-d
jni
头文件生成到jni文件夹(当前在<Project>\app\src\main目录下,所以.h所在的目录为<Project>\app\src\main\jni
)
-classpath
./java
指定去当前路径下java下寻找包名指定的类
这样再rebuild一下,就会生成so文件了