ndk的環境配置就不寫了,網上很多
首先新建一個項目,然後在包名下新建一個類,定義自己需要的native方法
public class SingatureClass {
//驗證包名
public native String verificationPackage(Object context);
//驗證簽名
public native String verificationSign(Object context);
}
其次要獲取到項目的簽名值
這裏需要注意的地方是debug包和release包的簽名是不一樣的,如果要獲取release包的簽名值,則需要把該方法生成的簽名值先寫入本地日誌, 然後從日誌中獲取簽名值,將獲取到的簽名值複製到.c文件中
public static String getSignature(Context context) {
try {
/** 通過包管理器獲得指定包名包含簽名的包信息 **/
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
/******* 通過返回的包信息獲得簽名數組 *******/
Signature[] signatures = packageInfo.signatures;
/******* 循環遍歷簽名數組拼接應用簽名 *******/
return signatures[0].toCharsString();
/************** 得到應用簽名 **************/
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
接下來生成.h文件
打開Terminal,
輸入cd app/src/main/java,鍵入Enter
然後輸入javah -d ../jni -classpath . -jni 包名.類名
如果出現錯誤:“錯誤: 編碼GBK的不可映射字符”,
則輸入javah -d ../jni -classpath . -jni -encoding UTF-8 包名.類名
在main目錄下新建jni文件夾,將生成的.h文件移動到jni目錄下
然後在jni目錄先新建c/c++文件
將.h中的生成的方法複製到新建的c文件中,並且添加引用
將簽名值和包名進行賦值
下面貼出代碼
#include "com_lee_signatureencryption_SingatureClass.h"
#include <jni.h>
#include <string.h>
#include <unistd.h>
/**
* 發佈的app 簽名,只有和本簽名一致的app 纔會返回 AUTH_KEY
* 這個RELEASE_SIGN的值是上一步用java代碼獲取的值
*/
const char* RELEASE_SIGN = "********92a864886f70d010";
const char* RELEASE_PACKAGE = "com.lee.signatureencryption";
JNIEXPORT jstring JNICALL Java_com_lee_signatureencryption_SingatureClass_verificationPackage
(JNIEnv *env, jobject jobj, jobject context_object){
jclass context_class = env->GetObjectClass(context_object);
//context.getPackageManager()
jmethodID methodId = env->GetMethodID(context_class, "getPackageManager", "()Landroid/content/pm/PackageManager;");
jobject package_manager_object = env->CallObjectMethod(context_object, methodId);
if (package_manager_object == NULL) {
return NULL;
}
//context.getPackageName()
methodId = env->GetMethodID(context_class, "getPackageName", "()Ljava/lang/String;");
jstring package_name_string = (jstring)env->CallObjectMethod(context_object, methodId);
if (package_name_string == NULL) {
return NULL;
}
const char* c_package = (char*)env->GetStringUTFChars(package_name_string, 0);
if(strcmp(c_package, RELEASE_PACKAGE) == 0) {
return (env)->NewStringUTF("package true");
} else {
return (env)->NewStringUTF("package error");
}
}
JNIEXPORT jstring JNICALL Java_com_lee_signatureencryption_SingatureClass_verificationSign
(JNIEnv *env, jobject jobj, jobject context_object){
jclass context_class = env->GetObjectClass(context_object);
//context.getPackageManager()
jmethodID methodId = env->GetMethodID(context_class, "getPackageManager", "()Landroid/content/pm/PackageManager;");
jobject package_manager_object = env->CallObjectMethod(context_object, methodId);
if (package_manager_object == NULL) {
return NULL;
}
//context.getPackageName()
methodId = env->GetMethodID(context_class, "getPackageName", "()Ljava/lang/String;");
jstring package_name_string = (jstring)env->CallObjectMethod(context_object, methodId);
if (package_name_string == NULL) {
return NULL;
}
env->DeleteLocalRef(context_class);
//PackageManager.getPackageInfo(Sting, int)
jclass pack_manager_class = env->GetObjectClass(package_manager_object);
methodId = env->GetMethodID(pack_manager_class, "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
env->DeleteLocalRef(pack_manager_class);
jobject package_info_object = env->CallObjectMethod(package_manager_object, methodId, package_name_string, 64);
if (package_info_object == NULL) {
return NULL;
}
env->DeleteLocalRef(package_manager_object);
//PackageInfo.signatures[0]
jclass package_info_class = env->GetObjectClass(package_info_object);
jfieldID fieldId = env->GetFieldID(package_info_class, "signatures", "[Landroid/content/pm/Signature;");
env->DeleteLocalRef(package_info_class);
jobjectArray signature_object_array = (jobjectArray)env->GetObjectField(package_info_object, fieldId);
if (signature_object_array == NULL) {
return NULL;
}
jobject signature_object = env->GetObjectArrayElement(signature_object_array, 0);
env->DeleteLocalRef(package_info_object);
//Signature.toCharsString()
jclass signature_class = env->GetObjectClass(signature_object);
methodId = env->GetMethodID(signature_class, "toCharsString", "()Ljava/lang/String;");
env->DeleteLocalRef(signature_class);
jstring signature_string = (jstring) env->CallObjectMethod(signature_object, methodId);
const char* c_sign = (char*)env->GetStringUTFChars(signature_string, 0);
//簽名一致 返回合法的 api key,否則返回錯誤
if(strcmp(c_sign, RELEASE_SIGN)==0) {
return (env)->NewStringUTF("sign true");
} else {
return (env)->NewStringUTF("sign error");
}
}
然後在jni 中添加Android.mk、Application.mk兩個文件
Android.mk
MY_LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PATH := $(MY_LOCAL_PATH)
include $(CLEAR_VARS)
LOCAL_MODULE := signature
LOCAL_SRC_FILES := signature.cpp
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_ABI := all
APP_PLATFORM := android-14
在app 下的build.gradle中添加配置
android{
......
sourceSets {
main {
jni.srcDirs = []
}
}
repositories {
flatDir {
dirs 'libs'
}
}
}
打開Terminal
輸入 cd app/src/main/jni Enter
輸入 ndk-build
等待幾分鐘時間,編譯成功後,將會生成libs和obj文件夾
libs中的文件就是我們需要的so
在main目錄下新建jniLibs文件夾,然後將libs中的文件全部拷貝到jniLibs中