Android JNI开发之c语言调用java方法

来源:互联网 发布:sql语句怎么打印空格 编辑:程序博客网 时间:2024/03/29 18:31

这篇文章主要讲解Android开发时在C方法中调用JAVA方法的步骤

一、前期知识准备

由于在C方法中调用JAVA方法需要运用反射的知识来。这里先来回顾一下java中是如何使用反射来调用一个类的方法的。
下边直接附上我在JAVA中利用反射的代码,具体的步骤在代码中有注释:
写一个类供反射访问:
package simpletest;public class MyClass {private void say(String msg){System.out.print("say::" + msg);} }
写一个利用反射调用该类中say方法的java类:
package simpletest;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class ReflectTest {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {//反射使用的步骤//1、获取类的字节码Class clazz = Class.forName("simpletest.MyClass");//2、获取指定的方法Method method = clazz.getDeclaredMethod("say", String.class);method.setAccessible(true);//3、调用该方法method.invoke(clazz.newInstance(), "我是反射出来的");}}
打印出来的结果为:say::我是反射出来的

二、在C语言中使用的具体步骤

在了解了JAVA中使用反射的步骤后,在C代码中利用反射也是类似的步骤。
下边直接放代码(具体的在代码中有详细的注释)
JNIAlipay\jni\Android.mk:
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_LDLIBS += -llogLOCAL_MODULE    := JNIAlipayLOCAL_SRC_FILES := JNIAlipay.cinclude $(BUILD_SHARED_LIBRARY)
JNIAlipay\jni\Application.mk:
APP_ABI := all
JNIAlipay\jni\JNIAlipay.c:
#include <jni.h>#include <stdlib.h>#include <string.h>#include <android/log.h>#define LOG_TAG "System.out"#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)//LOGI("info\n");  //打印日志的方法// LOGD("debug\n");/* * 将jstring类型 的字符串,转换为 char* 类型 */char*   Jstring2CStr(JNIEnv*   env,   jstring   jstr)// jstr 是java语言中的 String,该方法的目的就是调用   jstr.getByte("GB2312");{ char*   rtn   =   NULL; jclass   clsstring   =   (*env)->FindClass(env,"java/lang/String"); jstring   strencode   =   (*env)->NewStringUTF(env,"GB2312"); jmethodID   mid   =   (*env)->GetMethodID(env,clsstring,   "getBytes",   "(Ljava/lang/String;)[B"); jbyteArray   barr=   (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312"); jsize   alen   =   (*env)->GetArrayLength(env,barr); jbyte*   ba   =   (*env)->GetByteArrayElements(env,barr,JNI_FALSE); if(alen   >   0) {  rtn   =   (char*)malloc(alen+1);         //"\0"  memcpy(rtn,ba,alen);  rtn[alen]=0; } (*env)->ReleaseByteArrayElements(env,barr,ba,0);  // return rtn;}/** *一个c方法 * 调用MainActivity中的方法显示ProgressDialog */void showProgress(JNIEnv * env, jobject obj, char * jmsg){//1、获取类的字节码:查询jni.h返回jclss类型的方法:jclass  (*FindClass)(JNIEnv*, const char*);/** * 参数1:jni开发环境的引用 * 参数2:使用类的全名,注意要将其中的.换成/ */jclass jclazz = (*env)->FindClass(env,"com/example/jnialipay/MainActivity");//2、获取指定的方法 : jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);/** * 参数1:jni开发环境的引用 * 参数2:类引用 * 参数3:要调用的JAVA方法名称 * 参数4:要调用的JAVA方法的方法签名 * (获取方法签名:使用 javap -s com.example.jnialipay.MainActivity 可以获得所有方法的签名 * 注意这个命令执行的路径需要在项目路径/bin/classes下打开命令窗口来执行。获取JAVA类中所有的方法签名后, * 将我们要调用的方法签名copy过来就行了) */jmethodID jmethod = (*env)->GetMethodID(env,jclazz,"showProgress","(Ljava/lang/String;)V");//3、调用该方法:void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);/** * 参数1:jni开发环境的引用 * 参数2:是调用该函数的java对象的引用 * 参数3:jmethodID对象 * 参数4/5/6/...:可以是多个。是调用JAVA方法要传入的参数。 * 在java方法中参数为String类型,我们要将char *转化为jstring传入,不能直接使用char *类型 * */jstring msg = (*env)->NewStringUTF(env,jmsg);//将char * 类型转为jstring类型(*env)->CallVoidMethod(env,obj,jmethod,msg);}/** * 开始支付 * @param userid  用户名 * @param pwd 密码 * @param money 支付金额 * @return * 200 支付成功 * 400 支付失败  -  用户名、密码不正确 * 500 支付失败 -- 金额受限制 */JNIEXPORT jint JNICALL Java_com_example_jnialipay_MainActivity_pay  (JNIEnv * env, jobject obj, jstring name, jstring pwd, jint money){showProgress(env,obj,"本地数据打包");//调用上边的方法LOGI("本地数据打包");//打印log日志sleep(2);//休眠:单位为秒 模拟本地数据打包操作showProgress(env,obj,"联接服务器验证数据");//调用上边的方法LOGI("联接服务器验证数据");//打印log日志sleep(2);//休眠:单位为秒模拟联接服务器验证数据showProgress(env,obj,"联接服务器验证数据");//调用上边的方法LOGI("联接服务器验证数据");//打印log日志sleep(2);//休眠:单位为秒  模拟联接服务器进行支付// 获得用户名char * pUserId = Jstring2CStr(env,name);// 获得密码char * pPwd = Jstring2CStr(env,pwd);// 获得金额int mun = money;// 假设  用户名是abc 密码 123   金额最大,不能起过5000int result_user = strcmp(pUserId,"abc");//c语言中字符串的比较int result_pwd = strcmp(pPwd,"123");if(result_user == 0 && result_pwd == 0){ // 表明用户名密码正确if(money<5000){// 支付成功return 200;}else{// 金额受限return 500;}}else{//用户名,或密码不正确return 400;}};


JNIAlipay\src\com\example\jnialipay\MainActivity.java:
package com.example.jnialipay;import android.app.ProgressDialog;import android.os.Bundle;import android.os.Handler;import android.support.v7.app.ActionBarActivity;import android.text.TextUtils;import android.view.View;import android.widget.EditText;import android.widget.Toast;public class MainActivity extends ActionBarActivity {private EditText etName;private EditText etPwd;private EditText etMoney;private ProgressDialog proDlg;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}private void initView() {etName = (EditText) findViewById(R.id.et_name);etPwd = (EditText) findViewById(R.id.et_pwd);etMoney = (EditText) findViewById(R.id.et_money);proDlg = new ProgressDialog(this);proDlg.setTitle("提醒");proDlg.setMessage("正在处理,请稍候..");}public void btnClick(View v){final String etNameStr = etName.getText().toString().trim();final String etPwdStr = etPwd.getText().toString().trim();final String etMoneyStr = etMoney.getText().toString().trim();if(TextUtils.isEmpty(etNameStr)){Toast.makeText(this, "请输入用户名", 1).show();return;}if(TextUtils.isEmpty(etPwdStr)){Toast.makeText(this, "请输入密码", 1).show();return;}if(TextUtils.isEmpty(etMoneyStr)){Toast.makeText(this, "请输入要转账的金额", 1).show();return;}new Thread(){public void run() {int result = pay(etNameStr,etPwdStr,Integer.parseInt(etMoneyStr));handler.sendEmptyMessage(result);};}.start();}private Handler handler = new Handler(){public void handleMessage(android.os.Message msg) {dissProgress();switch (msg.what) {case 200:Toast.makeText(MainActivity.this, "支付成功", 1).show();break;case 400:Toast.makeText(MainActivity.this, "支付失败 --用户名、密码不正确", 1).show();break;case 500:Toast.makeText(MainActivity.this, "支付失败 --金额受限制", 1).show();break;default:break;}};};/** * 该方法 ,是让C代码中调用的,用于提示用户,当前的工作 * @param msg */public void showProgress(final String msg){// 该方法,会在子线程中调用,为了显示进度框,代码应应在主线程执行runOnUiThread(new Runnable() {@Overridepublic void run() {if (proDlg != null && proDlg.isShowing()) {proDlg.dismiss();}proDlg.setMessage(msg);proDlg.show();}});}private Handler handler2 = new Handler(){public void handleMessage(android.os.Message msg) {};};/** * 隐藏进度框 */public void dissProgress() {runOnUiThread(new Runnable() {@Overridepublic void run() {if (proDlg != null && proDlg.isShowing()) {proDlg.dismiss();}}});}/** * 支付的方法,这个方法写在c代码中 * @param userid  用户名 * @param pwd 密码 * @param money 支付金额 * @return * 200 支付成功 *  400 支付失败  -  用户名、密码不正确 *  500 支付失败 -- 金额受限制 */private native int pay(String userid,String pwd ,int money);static{System.loadLibrary("JNIAlipay");}}
JNIAlipay\res\layout\activity_main.layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >    <EditText        android:id="@+id/et_name"        android:hint="请输入账号"        android:layout_margin="10dp"        android:layout_width="match_parent"        android:layout_height="wrap_content"/>    <EditText        android:id="@+id/et_pwd"        android:hint="请输入密码"        android:layout_margin="10dp"        android:inputType="textPassword"        android:layout_width="match_parent"        android:layout_height="wrap_content"/>    <EditText        android:id="@+id/et_money"        android:hint="请输入金额"        android:layout_margin="10dp"        android:inputType="number"        android:layout_width="match_parent"        android:layout_height="wrap_content"/>    <Button        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:onClick="btnClick"        android:text="点击开始转账" /></LinearLayout>
如果想要直接下载项目的可以点击下边的链接免费下载源码:
点击打开链接
                                             
1 0
原创粉丝点击