NDK 调用 so 时的异常问题解决
这两天开始学习下android ndk的使用,给自己提了两个问题
1。 .so文件时怎么生成的?
2。 生成了so文件之后要怎么取调用呢
3。 为什么要用so文件,为什么要用java调用c/c++代码呢?
问题1:
站在巨人的肩膀上学习,大家可直接下载这位同学分享出来的项目学习和生成
https://github.com/wobiancao/NdkJniDemo
问题2:
(1)给我一个so文件,首先我需要知道这个so支持哪些方法,以下命令就可以查询
nm -D /Users/scucheri/AllMyProjects/AI_android/ndk/test_use_so/app/libs/armeabi/libNdkJniDemo.so
结果如下:
00000690 T Java_com_wobiancao_ndkjnidemo_ndk_JniUtils_getIv
00000610 T Java_com_wobiancao_ndkjnidemo_ndk_JniUtils_getKeyValue
000005e0 T Java_com_wobiancao_ndkjnidemo_ndk_JniUtils_getStringFormC
00003004 A __bss_start
U __cxa_atexit
00000000 w __cxa_begin_cleanup
00000000 w __cxa_call_unexpected
U __cxa_finalize
00000000 w __cxa_type_match
00000000 w __gnu_Unwind_Find_exidx
00003004 A _edata
00003004 A _end
U abort
00001d99 R iv
00001d68 R keyValue
U memcpy
可以看出来,支持的JNI方法有 Java_com_wobiancao_ndkjnidemo_ndk_JniUtils_getIv,Java_com_wobiancao_ndkjnidemo_ndk_JniUtils_getKeyValue 和 Java_com_wobiancao_ndkjnidemo_ndk_JniUtils_getStringFormC
(2)查询到方法之后那怎么调用这个方法呢? 先将 libNdkJniDemo.so 文件放入到libs目录下,然后 在app的gradle文件中 加入以下配置
android{
...
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
这时候就如果在android studio中的项目工程jniLibs目录下出现了这个so文件,就说明已经导入成功。
这时候需要写一个java类作为JNI接口,实现java对c代码的调用,需要特别注意的是,这个JNI接口类的package,className都必须和so文件中支持的方法保持一致,否则就会报错 method can’t found error
比如Java_com_wobiancao_ndkjnidemo_ndk_JniUtils_getIv ,若需要调用它,需要新建的java类为JniUtils ,package name为 com.wobiancao.ndkjnidemondk
代码如下:
package com.wobiancao.ndkjnidemo.ndk;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
/**
* Created by xy on 16/1/4.
*/
public class JniUtils {
public static native String getStringFormC();
public static native byte[] getKeyValue();
public static native byte[] getIv();
private static byte[]keyValue;
private static byte[]iv;
private static SecretKey key;
private static AlgorithmParameterSpec paramSpec;
private static Cipher ecipher;
static {
System.loadLibrary("NdkJniDemo"); //defaultConfig.ndk.moduleName
keyValue = getKeyValue();
iv = getIv();
if(null != keyValue && null !=iv) {
KeyGenerator kgen;
try {
kgen = KeyGenerator.getInstance("AES");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG","Crypto");
random.setSeed(keyValue);
kgen.init(128,random);
key =kgen.generateKey();
paramSpec =new IvParameterSpec(iv);
ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
} catch (NoSuchAlgorithmException e) {
} catch (NoSuchPaddingException e) {
} catch (NoSuchProviderException e) {
e.printStackTrace();
}
}
}
}
除了JNI的package name和className一定要与so文件中的配置保持一致之外,还需要注意:
在执行 System.loadLibrary(“NdkJniDemo”); 时,这个名字不是指so文件的全名“libNdkJniDemo“,不包含前面的lib。
(3)问题3:
见博文:
http://allenfeng.com/2016/11/06/what-you-should-know-about-android-abi-and-so/
* so机制让开发者最大化利用已有的C和C++代码,达到重用的效果,利用软件世界积累了几十年的优秀代码;
* so是二进制,没有解释编译的开消,用so实现的功能比纯java实现的功能要快;
* so内存分配不受Dalivik/ART的单个应用限制,减少OOM;
* 相对于java代码,二进制代码的反编译难度更大,一些核心代码可以考虑放在so中。
推荐阅读
-
NDK 调用 so 时的异常问题解决
-
PHP5 在调用 JAVA WebService 时遇到的各种问题解决方法_PHP教程
-
php-PHP调用.NET写的web service时异常,这一般是什么问题。异常错误信息如下
-
对于使用JDBC连接mysql数据时The server time zone value '¤¤°ê¼Ð·Ç®É¶¡'...的异常问题解决。
-
调用远程主机上的 RMI 服务时抛出 java.rmi.ConnectException: Connection refused to host: 127.0.0.1 异常原因及解决方案
-
PHP5 在调用 JAVA WebService 时遇到的各种问题解决方法_PHP教程
-
Android Studio-NDK开发(二)调用ndk开发生成的so和jar包
-
php-PHP调用.NET写的web service时异常,这一般是什么问题。异常错误信息如下
-
调用远程主机上的 RMI 服务时抛出 java.rmi.ConnectException: Connection refused to host: 127.0.0.1 异常原因及解决方案
-
对于使用JDBC连接mysql数据时The server time zone value '¤¤°ê¼Ð·Ç®É¶¡'...的异常问题解决。