为什么要有签名验证
假设“人民日报”接入了我们开发的sdk,“今日头条”没有接入我们的sdk,那么对于我们来说,当然不希望“今日头条”可以使用我们暴漏的接口,此时就有了“签名验证”。
如何实现
- 我们拿到“人民日报”的apk,通过 JarFile 拿到该apk的签名信息。
- 将该信息打入我们的aar包中
- 当“人民日报”访问我们暴漏的接口的时候要求传入Context,我们可以通过Context获取packageInfo中的signature。
- 比对aar中的签名信息跟获取到的packageinfo中的签名信息,如果匹配,才允许访问。
如何通过jarFile获取apk签名信息
1 | import java.io.File; |
如何将签名信息打入aar
可以在build.gradle中新建task,该task有两个任务:
- 通过JarFile获取签名string(参考以上代码)
- 将该信息copy到jni层(假设coreLib.cpp中)出于安全考虑
1 | task('writeApkSignature') << { |
如何通过context获取签名信息(jni的方式)
java方式
1
2
3PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 64);
Signature[] signatures = packageInfo.signatures;
String s = signatures[0].toCharsString();jni方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35char *getSignature(JNIEnv *env, jclass clazz, jobject contextObject) {
jclass native_class = env->GetObjectClass(contextObject);
//getPackageManager方法id
jmethodID pm_id = env->GetMethodID(native_class, "getPackageManager",
"()Landroid/content/pm/PackageManager;");
//context.getPackageManager()->packageManager
jobject pm_obj = env->CallObjectMethod(contextObject, pm_id);
jclass pm_clazz = env->GetObjectClass(pm_obj);
//获取pm.getpackageInfo的方法id
jmethodID package_info_id = env->GetMethodID(pm_clazz, "getPackageInfo",
"(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
jclass native_classs = env->GetObjectClass(contextObject);
//context.getPackageName方法id
jmethodID mId = env->GetMethodID(native_classs, "getPackageName", "()Ljava/lang/String;");
//返回packageName
jstring pkg_str = static_cast<jstring>(env->CallObjectMethod(contextObject, mId));
//获取packageInfo
jobject pi_obj = env->CallObjectMethod(pm_obj, package_info_id, pkg_str, 64);
jclass pi_clazz = env->GetObjectClass(pi_obj);
//获取packageInfo的成员变量signature的id
jfieldID signatures_fieldId = env->GetFieldID(pi_clazz, "signatures",
"[Landroid/content/pm/Signature;");
//获取packageInfo的signature
jobject signatures_obj = env->GetObjectField(pi_obj, signatures_fieldId);
jobjectArray signaturesArray = (jobjectArray) signatures_obj;
//获取signatures[0]
jobject signature_obj = env->GetObjectArrayElement(signaturesArray, 0);
jclass signature_clazz = env->GetObjectClass(signature_obj);
jmethodID string_id = env->GetMethodID(signature_clazz, "toCharsString",
"()Ljava/lang/String;");
//调用signatures[0]的toCharsString方法返回string串
jstring str = static_cast<jstring>(env->CallObjectMethod(signature_obj, string_id));
return (char *) env->GetStringUTFChars(str, 0);
}