NDK 调用 so 时的异常问题解决

来源:互联网 发布:苹果系统切换windows 编辑:程序博客网 时间:2024/06/18 17:53

这两天开始学习下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_getIv00000610 T Java_com_wobiancao_ndkjnidemo_ndk_JniUtils_getKeyValue000005e0 T Java_com_wobiancao_ndkjnidemo_ndk_JniUtils_getStringFormC00003004 A __bss_start         U __cxa_atexit00000000 w __cxa_begin_cleanup00000000 w __cxa_call_unexpected         U __cxa_finalize00000000 w __cxa_type_match00000000 w __gnu_Unwind_Find_exidx00003004 A _edata00003004 A _end         U abort00001d99 R iv00001d68 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中。
原创粉丝点击