Android NDK之静态/动态注册Native方法

一、简介

关于NDK有两种方法注册:静态注册动态注册

  • 静态注册: 就是直接在Java文件里写个native方法 然后再c/c++文件中实现这个方法就行了;
  • 动态注册: 就是为了不要写很长的方法名,用JNI_OnLoad方法实现预注册,即当执行System.LoadLibrary()方法时候就把需要调用的方法给注册了,效率要高 Android就是采用此方法;

下面就以示例来说明静态注册动态注册以及C层调用Java层方法

二、代码实现

Github:NDKDemo

Java层Native方法定义

package com.cloudwise.ndk;
import android.util.Log;public class NDKUtil {// 静态注册Native方法public native static String stringFromJNI();// 静态注册Native方法public native static void setJNILogEnable(int type);// 动态注册Native方法public native static int getVersionCode();// 动态注册Native方法public native static String getVersion(int code);// 动态注册Native方法,并且C回调Java方法public native static void callJavaString();// 动态注册Native方法,并且C回调Java方法public native static void callJavaVoid();// C调用Java方法(带返回值)public static String getStringToC(String name){Log.e("CLOUDWISE", "name : " + name);return "C From Java";}// C调用Java方法(不带返回值)public static void getVoidToC(int id, String name){Log.e("CLOUDWISE", "id : " + id + " ---- name : " + name);}
}

C层代码

common.h

#ifndef NDKDEMO_COMMON_H
#define NDKDEMO_COMMON_H#ifdef __cplusplus
extern "C" {
#endif#define LOGOPEN 1 //日志开关,1为开,其它为关
#define LOG_TAG    "[CLOUDWISE-NDK]"
#if(LOGOPEN==1)#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)#define LOGD(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#else
#define LOGI(...) NULL#define LOGE(...) NULL#define LOGD(...) NULL
#endif#ifdef __cplusplus
}
#endif#endif //NDKDEMO_COMMON_H

native-lib.c

#include <jni.h>
#include <string.h>
#include <android/log.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include "common.h"static JavaVM *j_vm = NULL;
static jclass j_class = NULL;static jint debug = 1;/*** 静态注册的Native方法* @param env* @param arg* @return*/
JNIEXPORT jstring JNICALL Java_com_cloudwise_ndk_NDKUtil_stringFromJNI(JNIEnv *env,jclass arg) {jstring hello = "Hello ---- from ---- C";if(debug == 1){LOGE("stringFromJNI ---- Hello ---- from ---- C");}return (*env)->NewStringUTF(env, hello);
}/*** 静态注册的Native方法* @param env* @param arg* @param type*/
JNIEXPORT void JNICALL Java_com_cloudwise_ndk_NDKUtil_setJNILogEnable(JNIEnv *env,jclass arg, jint type){if(type == 1){debug = 1;} else {debug = 0;}
}/*** 动态注册的Native方法* @param env* @param arg* @return*/
JNIEXPORT jint JNICALL getVersionCode(JNIEnv *env, jclass arg){if(debug == 1){LOGE("getVersionCode ----------- 10");}return 10;
}/*** 动态注册的Native方法* @param env* @param arg* @param code* @return*/
JNIEXPORT jstring JNICALL getVersion(JNIEnv *env, jclass arg, jint code){if(debug == 1){LOGE("getVersion ----------- 1.2.6");}jstring ver = "1.2.6";return (*env)->NewStringUTF(env, ver);
}/*** C调用Java方法(带参数不带返回值)*/
void callVoidFromJava(){JNIEnv *env;(*j_vm)->AttachCurrentThread(j_vm, &env, NULL);jmethodID methodid = (*env)->GetStaticMethodID(env, j_class, "getVoidToC", "(ILjava/lang/String;)V");(*env)->CallStaticVoidMethod(env, j_class, methodid, 10, (*env)->NewStringUTF(env, "C-Name"));if(debug == 1) {LOGE("callVoidFromJava Java To C");}
}/*** C调用Java方法(带参数带返回值)*/
void callStringFromJava(){JNIEnv *env;(*j_vm)->AttachCurrentThread(j_vm, &env, NULL);jmethodID methodid = (*env)->GetStaticMethodID(env, j_class, "getStringToC", "(Ljava/lang/String;)Ljava/lang/String;");jstring str = (jstring)(*env)->CallStaticObjectMethod(env, j_class, methodid,(*env)->NewStringUTF(env, "C-Name"));char* java = (char*)(*env)->GetStringUTFChars(env, str, NULL);if(debug == 1) {LOGE("callStringFromJava Java To C : %s", java);}
}/*** 动态注册的Native方法,然后调用Java方法* @param env* @param arg*/
JNIEXPORT void JNICALL callJavaString(JNIEnv *env, jclass arg) {callStringFromJava();
}/*** 动态注册的Native方法,然后调用Java方法* @param env* @param arg*/
JNIEXPORT void JNICALL callJavaVoid(JNIEnv *env, jclass arg) {callVoidFromJava();
}static JNINativeMethod mMethods[] = {{"getVersionCode", "()I", (void*)getVersionCode},{"getVersion", "(I)Ljava/lang/String;", (void*)getVersion},{"callJavaString", "()V", (void*)callJavaString},{"callJavaVoid", "()V", (void*)callJavaVoid}
};static int registerNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods){jclass clazz;clazz = (*env)->FindClass(env, className);if(clazz == NULL){return -1;}j_class = (jclass)(*env) -> NewGlobalRef(env, (jobject)clazz);if((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0){return -1;}return 0;
}static int registerNative(JNIEnv* env){return registerNativeMethods(env, "com/cloudwise/ndk/NDKUtil", mMethods, sizeof(mMethods)/ sizeof(mMethods[0]));
}JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){LOGE("JNI_OnLoad ------------------------------ ");JNIEnv* env = NULL;jint result = -1;/** JavaVM::GetEnv 原型为 jint (*GetEnv)(JavaVM*, void**, jint);* GetEnv()函数返回的  Jni 环境对每个线程来说是不同的,* 由于Dalvik虚拟机通常是Multi-threading的。每一个线程调用JNI_OnLoad()时,* 所用的JNI Env是不同的,因此我们必须在每次进入函数时都要通过vm->GetEnv重新获取*/if((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK){return -1;}if(registerNative(env) != JNI_OK){return -1;}j_vm = vm;//cloudwise_init(1);result = JNI_VERSION_1_4;return result;
}

Java层调用代码

package com.cloudwise.ndk;import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;import java.io.InputStream;public class CrashActivity extends AppCompatActivity implements View.OnClickListener {TextView txt;Button btn, btn_debug, btn_close, btn_ver_code, btn_ver, btn_logcat;// Used to load the 'native-lib' library on application startup.static {System.loadLibrary("native-lib");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_crash);// Example of a call to a native methodtxt = (TextView) findViewById(R.id.sample_text);btn = (Button)findViewById(R.id.btn);btn.setOnClickListener(this);btn_debug = (Button)findViewById(R.id.btn_debug);btn_debug.setOnClickListener(this);btn_close = (Button)findViewById(R.id.btn_close);btn_close.setOnClickListener(this);btn_ver = (Button)findViewById(R.id.btn_ver);btn_ver.setOnClickListener(this);btn_ver_code = (Button)findViewById(R.id.btn_ver_code);btn_ver_code.setOnClickListener(this);btn_logcat = (Button)findViewById(R.id.btn_string);btn_logcat.setOnClickListener(this);btn = (Button)findViewById(R.id.btn_void);btn.setOnClickListener(this);}private void btnClick(){txt.setText(NDKUtil.stringFromJNI());//Log.e("CLOUDWISE", "stringFromJNI-------");}private void btnDebug(){NDKUtil.setJNILogEnable(1);}private void btnClose(){NDKUtil.setJNILogEnable(0);}private void btnVer(){txt.setText(NDKUtil.getVersion(1));}private void btnVerCode(){txt.setText(NDKUtil.getVersionCode()+"");}private void btnString(){NDKUtil.callJavaString();}private void btnVoid(){NDKUtil.callJavaVoid();}@Overridepublic void onClick(View v) {switch (v.getId()){case R.id.btn:btnClick();break;case R.id.btn_debug:btnDebug();break;case R.id.btn_close:btnClose();break;case R.id.btn_ver:btnVer();break;case R.id.btn_ver_code:btnVerCode();break;case R.id.btn_string:btnString();break;case R.id.btn_void:btnVoid();break;}}
}

Java层布局代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:id="@+id/sample_text"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="10dp"android:text="" /><Buttonandroid:layout_width="match_parent"android:layout_height="50dp"android:text="JNI调用"android:id="@+id/btn"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="10dp"/><Buttonandroid:layout_width="match_parent"android:layout_height="50dp"android:text="VersionCode"android:id="@+id/btn_ver_code"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="10dp"/><Buttonandroid:layout_width="match_parent"android:layout_height="50dp"android:text="Version"android:id="@+id/btn_ver"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="10dp"/><Buttonandroid:layout_width="match_parent"android:layout_height="50dp"android:text="开启JNI日志"android:id="@+id/btn_debug"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="10dp"/><Buttonandroid:layout_width="match_parent"android:layout_height="50dp"android:text="关闭JNI日志"android:id="@+id/btn_close"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="10dp"/><Buttonandroid:layout_width="match_parent"android:layout_height="50dp"android:text="C调Java(带返回值)"android:id="@+id/btn_string"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="10dp"/><Buttonandroid:layout_width="match_parent"android:layout_height="50dp"android:text="C调Java(不带返回值)"android:id="@+id/btn_void"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="10dp"/></LinearLayout></ScrollView></LinearLayout>

布局界面

效果图

运行结果

[CLOUDWISE-NDK]: stringFromJNI ---- Hello ---- from ---- C
[CLOUDWISE-NDK]: getVersionCode ----------- 10
[CLOUDWISE-NDK]: getVersion ----------- 1.2.6
CLOUDWISE: name : C-Name
[CLOUDWISE-NDK]: callStringFromJava Java To C : C From Java
CLOUDWISE: id : 10 ---- name : C-Name
[CLOUDWISE-NDK]: callVoidFromJava Java To C

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/446892.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

概率论 条件概率 全概率 贝叶斯公式

常用知识点 条件概率 1.P(B|A)1表示A发生的情况下B必然发生 A属于B 2.可列可加性 P(BUC|A)P(B|A)P(C|A) 3.P(B|A)的样本空间为A,A与B都发生了 大题解答思路 1.首先设取出一件商品为次品为事件A 2.写B1:甲生产,B2:乙生产 PB1…PB2… P(A|B1)…P(A|B2)… 3.写PAPB1*P(A|B1)……

使用命令行的方式,将ini配置文件中的配置信息传递给程序

ini配置文件 {"device_type": "fake","device_socket": "192.168.1.108:5000"} 使用rpc的方式 ./bin/hsm_device_apitest --gtest_filter"*aes_test" --device-type rpc --device-socket 192.168.1.108:5000 使用fake的方…

C语言学习:malloc()函数

函数声明&#xff1a; void *malloc(size_t size)头文件&#xff1a; #include <stdio.h>函数描述&#xff1a; 分配所需的内存空间&#xff0c;并返回一个指向它的指针。 参数&#xff1a; size – 内存块的大小&#xff0c;以字节为单位。 返回值&#xff1a; 该…

java 希尔排序

希尔排序(更高效的插入排序) 减少最小数在最后一位的情况下要循环的次数 思路: 把数组按增量(n/2)分组,对每一组使用插入排序去排序交换位置,然后不停地增量/2,直到其为1时,结束 分组:如n/25 891723 8与3为一组 从不包含本身的数开始数两种实现方法: 交换法(效率较低) 移动法…

使用gtest进行自己的单独测试的代码介绍

命令行 ./bin/hsm_device_apitest --gtest_filter"*aes_test" --device-type rpc --device-socket 192.168.1.108:5000 命令详解 进入工程文件&#xff0c;mkdir build&#xff0c;cd build在build的文件夹下面执行cmake命令和make命令之后&#xff0c;会在build文…

C语言学习:%d、2d、02d、.2d的区别

%d&#xff1a;为普通的输出。 %2d&#xff1a;按宽度为2输出&#xff0c;右对齐方式输出。若不够两位&#xff0c;左边补空格。 %02d&#xff1a;同样宽度为2&#xff0c;右对齐方式。位数不够&#xff0c;左边补0。 %.2d&#xff1a;从执行效果来看&#xff0c;与%02d一样…

计算机系统基础 数据的表示和存储

数制和编码 1.信息的二进制编码 2.进制转换必须要知道: 1)使用哪一个进制(二,八…) 2)定点数还是浮点数(关于小数点的问题) 3)编码问题----原码,补码,反码,移码 3.进制转换 1)R进制转十进制(按权展开) ----R进制 ----八进制与十六进制 ----R转换为十进制 2)十进制转换为R…

C++中vector章节iterator与const_iterator及const iterator区别

C目前倾向于使用迭代器遍历容器中的元素&#xff0c;而不是使用下标访问的方式来访问容器中的元素。可以使用iterator和const_iterator来访问元素&#xff0c;但是const类型的容器&#xff0c;那么只能用const_iterator来遍历。区别在于iterator可以改变元素的数值&#xff0c;…

Android查看当前应用已经加载的so库

源代码&#xff1a; private static List<String> allSOLists new ArrayList<String>();/** * 获取全部已加载的SO库*/private void getAllSOLoaded(){allSOLists.clear();// 当前应用的进程IDint pid Process.myPid();String path "/proc/" pid &q…

Android 进程监控(top命令)

文章目录一、查看top命令Android N&#xff08;7.1系统&#xff0c;level 25&#xff09; 及之前Android O&#xff08;8.0系统&#xff0c;level 26&#xff09; 及之后二、top -n [number]Android N&#xff08;7.1系统&#xff0c;level 25&#xff09; 及之前Android O&…

java 快速排序

快速排序 对冒泡排序的一种改进 思路: 一趟排序后,选取一个中间值,数组被分为比中间值小的部分,比中间值大的部分;再对左右两部分分别递归排序 代码实现 import java.util.Arrays;public class QuickSort {public static void main(String[] args) {int[] arr {-9, 78, 0, 2…

C++字符串的个人理解

String string是字符串&#xff0c;在声明一个字符串的时候&#xff0c;比如string a;这个过程是在栈上进行的&#xff0c;但是如果给这个字符串分配内存空间&#xff0c;这段区间是存储在堆上的&#xff0c;因此最好在声明字符串的时候就要指出字符串的大小和对其进行初始化s…

Android 基础性能数据获取(/proc/)

一、系统内存 读取命令&#xff1a; /proc/meminfoJava代码&#xff1a; private void click(){try{String cmd "/proc/meminfo";BufferedReader reader new BufferedReader(new InputStreamReader(new FileInputStream(cmd)), 1000);StringBuilder sb new Stri…

物理 常见力与牛顿三定律

常用知识点 动量 dmvdmvdvm p-mv- f-dp-/dtma- 开普勒第三定律 r1^3__k只与恒星质量有关 T^2 总结 1.电梯匀速就相当于在地面,加速或减速就会有一个a 2.当合外力为0时,物体保持静止或匀速直线运动 3.力是改变物体运动状态的原因 4.重力在地球两极最大,赤道最小,随纬度…

Java命令:jmap — 打印指定进程的共享对象内存映射或堆内存细节

文章目录一、前言二、命令介绍三、使用实例1、jmap -heap [pid]2、jmap -histo[:live] [pid]3、jmap -histo[:live] [pid] |grep "[关键字1]\|[关键字2]"4、jmap -dump:live,formatb,filea.log [pid]四、总结一、前言 jdk安装后会自带一些小工具&#xff0c;jmap命令…

C++vector相关学习,我的理解

vector的初始化方式 1&#xff0c;使用拷贝初始化时候&#xff0c;即使用的时候&#xff0c;只可以提供一个初始值2&#xff0c;如果提供一个类内初始值&#xff0c;只可以使用拷贝初始化或者使用花括号的方式初始化3&#xff0c;如果提供的是初始元素值的列表&#xff0c;只可…

概率论 一维随机变量

随机变量 离散型随机变量:有限个或无限可列个 连续型随机变量 分布函数F(X) 范围是[a,b) 包含能取到a以及a之前的值的概率相加 分布律(概率分布) 1.所有概率相加为1 2.WX-1,计算出每一个对应的W,然后如果有相同的W就合并其概率,最后一一对应P(x)即可 概率密度函数(密度) …

Linux命令:grep命令详解

grep常用参数说明 grep [OPTIONS] PATTERN [FILE...] grep [OPTIONS] [-e PATTERN]... [-f FILE]... [FILE...]OPTIONS:-e: 使用正则搜索-i: 不区分大小写-v: 查找不包含指定内容的行-w: 按单词搜索-c: 统计匹配到的次数-n: 显示行号-r: 逐层遍历目录查找-A: 显示匹配行及后…

ECC密钥结构和密码学基础

参考链接 密码学基础3&#xff1a;密钥文件格式完全解析ECC数据结构

JAVA牛客专项练习2020.12.31

1.使用迭代器的remove方法&#xff0c;可以边遍历边删除元素 2.线程 启动线程 new thread&#xff08;&#xff09;.start&#xff08;&#xff09; new thread&#xff08;new runnable&#xff08;&#xff09;&#xff09;.start&#xff08;&#xff09; 普通方法&#xf…