JNI方法的静态注册和动态注册RegisterNatives

代码结构如下:
Android下的Java代码 仍然还是使用了eclipse开发环境 这里在NDKUtils.java文件里定义了所有的本地方法
这里写图片描述
Linux下的C代码 这里是在Linux系统目录下新建的文件 其中libs/和obj/都是由ndk-build编译后编译器产生
这里写图片描述

点击查看完整项目代码JniDemo-master

// MainActivity.java
public class MainActivity extends Activity  implements View.OnClickListener {

    private Button btnJni1, btnJni2, btnJni3;
    private TextView tvShowInfo;
    private NDKUtils jniUtil;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
         init();
    }

    private void init() {
        jniUtil = new NDKUtils();
        btnJni1 = (Button) findViewById(R.id.btnJni1);
        btnJni1.setOnClickListener(this);
        btnJni2 = (Button) findViewById(R.id.btnJni2);
        btnJni2.setOnClickListener(this);
        btnJni3 = (Button) findViewById(R.id.btnJni3);
        btnJni3.setOnClickListener(this);
        tvShowInfo = (TextView) findViewById(R.id.tvShowInfo);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btnJni1:
                tvShowInfo.setText(String.format("【静态调用Jni】获取String,输出为:\n %s",
                jniUtil.getVipString()));
                break;
            case R.id.btnJni2:
                tvShowInfo.setText(String.format("【静态调用Jni】输入vip,加密输出为:\n %s", 
                jniUtil.staticGenerateKey("vip")));
                break;
            case R.id.btnJni3:
                tvShowInfo.setText(String.format("【动态调用Jni】输入test,加密输出为:\n %s", 
                jniUtil.dynamicGenerateKey("test")));
                break;
            default:
                break;
        }
    }
}
// NDKUtils.java
public class NDKUtils {
    static {
        System.loadLibrary("zzyJni");  
    }

    public native String  getVipString();
    public native String  staticGenerateKey(String name);
    public native String  dynamicGenerateKey(String name);
}

这次的编译没有使用windows下的工具Cygwin64
而是直接在Linux系统下使用ndk-build工具生成对应的动态库(/libs/armeabi/libzzyJni.so)
直接使用ndk-build脚本编译出动态库也是非常简单的 在Linux宿主机上不需要安装和配置
只需要把android-ndk-r14b-linux-x86_64.zip解压到机器上 通过export导入路径到系统配置下就能直接使用

操作方法:
1 下载Linux版本的android-ndk-r14b-linux-x86_64.zip (我的Linux设备为Ubuntu64位操作系统)
2 导入ndk目录到系统配置,这里我使用了仅为我当前登录的用户有效
3 到/JniDemo-master/jni/目录下直接执行ndk-build脚本生成libs/和obj/目录以及动态库
4 拷贝动态库libzzyJni.so到eclipse对应的/libs/armeabi/libzzyJni.so
5 编译安卓应用程序到手机

这里写图片描述

NDK脚本的导入方法:
android-ndk-r14b-linux-x86_64/目录下执行两条export导入命令

/android-ndk-r14b$ export ANDROID_NDK=/home/admin/tools/android-ndk-r14b
/android-ndk-r14b$ export PATH=$PATH:$ANDROID_NDK

或者写成脚本

#Android NDK export_ndk.sh
export ANDROID_NDK=/home/admin/tools/android-ndk-r14b
export PATH=$PATH:$ANDROID_NDK

执行脚本 source export_ndk.sh
这里不是执行 sh export_ndk.sh
当在一个终端shell中执行一个sh脚本,本质是创建一个子进程来执行sh脚本中的命令,当执行export时,变量加入子进程的环境变量(而非父进程shell). 当脚本执行结束,子进程销毁. 返回父进程,父进程的环境变量没有任何变化
若希望嵌入linux启动时加入的环境变量, 可以直接将export的环境变量添加到/etc/profile
若希望在ubuntu上为特定用户添加环境变量,可以在~/.bashrc文件中添加

在/JniDemo-master目录下执行ndk-build脚本生成obj/和libs/libzzyJni.so动态库

/JniDemo-master$ ndk-build 

还在使用古老的eclipse 是因为已经有一段时间没有做安卓项目 所以没有使用Android studio
如果使用AS开发的话 就不需要手动编写 Android.mk 等编译的脚本文件
这里关于编译脚本中指定使用哪种架构的CPU还做了区分armeabi或者armeabi-v7a 或者其他类型
在Application.mk中可以看到我已经指定编译的CPU类型为 armeabi

APP_PLATFORM = android-23  
APP_ABI := armeabi
APP_STL := stlport_static  
APP_OPTIM := debug  

就做个简单介绍
Android 设备的CPU类型(通常称为”ABIs”)
armeabiv-v7a: 第7代及以上的 ARM 处理器。2011年15月以后的生产的大部分Android设备都使用它.
arm64-v8a: 第8代、64位ARM处理器,很少设备,三星 Galaxy S6是其中之一。
armeabi: 第5代、第6代的ARM处理器,早期的手机用的比较多。
x86: 平板、模拟器用得比较多。
x86_64: 64位的平板。

最后关于查看库中存在哪些函数方法:
使用nm命令失败的话 nm: no symbols
可以使用

 $ objdump -tT libzzyJni.so

运行在JM虚拟机上的Java代码是怎么样找到对应的本地方法的
这里有两种方法可以找到
1 C/C++代码的函数名以包名加上函数声明的形式让Java代码找到 属于静态方式
2 C/C++通过JNIEnv中的RegisterNatives方法注册函数名 属于动态方式

动态注册方式:

#include <jni.h>

static JNINativeMethod methods[] = {
        {"dynamicGenerateKey", "(Ljava/lang/String;)Ljava/lang/String;", (void *) native_dynamic_key},
};
static int registerNativeMethods(JNIEnv *env, const char *className, 
   JNINativeMethod *gMethods, int numMethods) {
   jclass clazz;
   clazz = (*env)->FindClass(env, className);
   if (clazz == NULL) {
       return JNI_FALSE;
   }
   if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
       return JNI_FALSE;
   }
   return JNI_TRUE;
}

static int registerNatives(JNIEnv *env) {
    const char *className = "demo/jnidemo/NDKUtils"; //指定注册的类
    return registerNativeMethods(env, className, methods, sizeof(methods) / sizeof(methods[0]));
}

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){
    JNIEnv* env = NULL;
    jint result = -1;
    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        return -1;
    }
    assert(env != NULL);

    if (!registerNatives(env)){
        return -1;
    }
    return JNI_VERSION_1_4;
}

JNI_OnLoad函数作为JNI加载的入口,直接在这里进行函数的动态注册

点击查看完整项目代码JniDemo-master

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值