由于Android应用程序大多使用Java编写,所有很容易通过反编译获取源代码,因此为了保持核心算法,逻辑的安全性,大多应用程序将该部分使用c或c++实现,例如:用户的登陆,底层采用c或c++代码编写。下面将演示简单的c语言验证用户名和密码正确性,实现登录。
1.创建Android应用程序
创建过程与一般android应用程序类似,添加2个EditText和1个Button,示例图如下
布局文件
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 <EditText 7 android:id="@+id/et1" 8 android:layout_width="fill_parent" 9 android:layout_height="wrap_content" 10 android:hint="用户名"/> 11 <EditText 12 android:id="@+id/et2" 13 android:layout_width="fill_parent" 14 android:layout_height="wrap_content" 15 android:hint="密码"/> 16 <Button 17 android:id="@+id/bt1" 18 android:layout_width="wrap_content" 19 android:layout_height="wrap_content" 20 android:hint="登录"/> 21 </LinearLayout>
2.添加Native方法
public native int login(String username,String password);
3.获取相应的头文件
D:\Android\ndk_login\src>javah com.forsta.login.MainActivity
得到com_forsta_login_MainActivity.h文件
com_forsta_login_MainActivity.h
1 /* DO NOT EDIT THIS FILE - it is machine generated */ 2 #include <jni.h> 3 /* Header for class com_forsta_login_MainActivity */ 4 5 #ifndef _Included_com_forsta_login_MainActivity 6 #define _Included_com_forsta_login_MainActivity 7 #ifdef __cplusplus 8 extern "C" { 9 #endif 10 /* 11 * Class: com_forsta_login_MainActivity 12 * Method: login 13 * Signature: (Ljava/lang/String;Ljava/lang/String;)I 14 */ 15 JNIEXPORT jint JNICALL Java_com_forsta_login_MainActivity_login 16 (JNIEnv *, jobject, jstring, jstring); 17 18 #ifdef __cplusplus 19 } 20 #endif 21 #endif
4.添加jni文件夹,Android.mk,login.c文件
login.c
1 #include <stdio.h> 2 #include <jni.h> 3 #include <malloc.h> 4 #include <string.h> 5 #include "com_forsta_login_MainActivity.h" 6 7 /** 8 * 返回值 char* 这个代表char数组的首地址 9 * Jstring2CStr 把java中的jstring的类型转化成一个c语言中的char 字符串 10 */ 11 char* Jstring2CStr(JNIEnv* env, jstring jstr) 12 { 13 char* rtn = NULL; 14 jclass clsstring = (*env)->FindClass(env,"java/lang/String"); //String 15 jstring strencode = (*env)->NewStringUTF(env,"GB2312"); // 得到一个java字符串 "GB2312" 16 jmethodID mid = (*env)->GetMethodID(env,clsstring, "getBytes", "(Ljava/lang/String;)[B"); //[ String.getBytes("gb2312"); 17 jbyteArray barr= (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312"); 18 jsize alen = (*env)->GetArrayLength(env,barr); // byte数组的长度 19 jbyte* ba = (*env)->GetByteArrayElements(env,barr,JNI_FALSE); 20 if(alen > 0) 21 { 22 rtn = (char*)malloc(alen+1); //"\0" 23 memcpy(rtn,ba,alen); 24 rtn[alen]=0; 25 } 26 (*env)->ReleaseByteArrayElements(env,barr,ba,0); // 27 return rtn; 28 } 29 30 //登录判断逻辑 31 int login(char*username,char*password) 32 { 33 char*user="forsta"; 34 char*pwd="123456"; 35 int i=0,j=0; 36 if(strcmp(user,username)!=0 ||strcmp(password,pwd)!=0){ 37 return 404; 38 } 39 return 200; 40 } 41 42 JNIEXPORT jint JNICALL Java_com_forsta_login_MainActivity_login 43 (JNIEnv *env, jobject obj, jstring username, jstring pwd){ 44 char*name=Jstring2CStr(env,username); 45 char*password=Jstring2CStr(env,pwd); 46 return login(name,password); 47 48 }
Android.mk
1 LOCAL_PATH := $(call my-dir) 2 include $(CLEAR_VARS) 3 LOCAL_MODULE := login 4 LOCAL_SRC_FILES := login.c 5 include $(BUILD_SHARED_LIBRARY)
5.编译,加载库文件
[email protected] /cygdrive/d/android/ndk_login
$ ndk-build
Android NDK: WARNING: APP_PLATFORM android-18 is larger than android:minSdkVersion 8 in ./AndroidManifest.xml
[armeabi] Compile thumb : login <= login.c
jni/login.c: In function ‘Jstring2CStr‘:
jni/login.c:22:4: warning: incompatible implicit declaration of built-in function ‘memcpy‘ [enabled by default]
[armeabi] SharedLibrary : liblogin.so
[armeabi] Install : liblogin.so => libs/armeabi/liblogin.so
加载库文件
static{
System.loadLibrary("login");
}
6.登录实现
1 bt.setOnClickListener(new OnClickListener() { 2 3 @Override 4 public void onClick(View v) { 5 String username=t1.getText().toString().trim(); 6 String pwd=t2.getText().toString().trim(); 7 int result =login(username,pwd); 8 if(result==200) 9 { 10 Toast.makeText(getApplicationContext(), "登录成功,code=200", 1).show(); 11 }else{ 12 13 Toast.makeText(getApplicationContext(), "登录失败,code=404", 1).show(); 14 } 15 16 } 17 });
7.显示结果
Android技术12:NDK模拟登陆