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.pswp.cn/news/446892.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446892.shtml
英文地址,請注明出處:http://en.pswp.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…