├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── wxmylife │ │ └── jni │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── wxmylife │ │ │ └── jni │ │ │ ├── JNIUtils.java │ │ │ └── MainActivity.java │ ├── jni │ │ ├── com_wxmylife_jni_JNIUtils.h │ │ └── sign.cpp │ └── res │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── wxmylife │ └── jni │ └── ExampleUnitTest.java ├── build.gradle ├── gif ├── a.gif └── b.gif ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img ├── 1.png ├── 10.png ├── 11.png ├── 13.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── 8.png └── 9.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | Android 39 | 40 | 41 | Android > Lint > Accessibility 42 | 43 | 44 | Android > Lint > Correctness 45 | 46 | 47 | Android > Lint > Internationalization 48 | 49 | 50 | Android > Lint > Internationalization > Bidirectional Text 51 | 52 | 53 | Android > Lint > Performance 54 | 55 | 56 | Android > Lint > Security 57 | 58 | 59 | Android > Lint > Usability 60 | 61 | 62 | Assignment issuesJava 63 | 64 | 65 | Class structureJava 66 | 67 | 68 | Code style issuesJava 69 | 70 | 71 | Control FlowGroovy 72 | 73 | 74 | Control flow issuesJava 75 | 76 | 77 | Data flow issuesJava 78 | 79 | 80 | Dependency issuesJava 81 | 82 | 83 | Encapsulation issuesJava 84 | 85 | 86 | Gradle 87 | 88 | 89 | Groovy 90 | 91 | 92 | HTML 93 | 94 | 95 | Inheritance issuesJava 96 | 97 | 98 | Initialization issuesJava 99 | 100 | 101 | Internationalization issuesJava 102 | 103 | 104 | J2ME issuesJava 105 | 106 | 107 | JUnit issuesJava 108 | 109 | 110 | Java 111 | 112 | 113 | Java language level migration aidsJava 114 | 115 | 116 | JavaBeans issuesJava 117 | 118 | 119 | Memory issuesJava 120 | 121 | 122 | Numeric issuesJava 123 | 124 | 125 | Performance issuesJava 126 | 127 | 128 | Portability issuesJava 129 | 130 | 131 | Potentially confusing code constructsGroovy 132 | 133 | 134 | Probable bugsGradle 135 | 136 | 137 | Probable bugsGroovy 138 | 139 | 140 | Probable bugsJava 141 | 142 | 143 | Properties Files 144 | 145 | 146 | Properties FilesJava 147 | 148 | 149 | Resource management issuesJava 150 | 151 | 152 | Serialization issuesJava 153 | 154 | 155 | TestNGJava 156 | 157 | 158 | Threading issuesGroovy 159 | 160 | 161 | Threading issuesJava 162 | 163 | 164 | Visibility issuesJava 165 | 166 | 167 | 168 | 169 | Android 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 191 | 192 | 193 | 194 | 195 | 1.8 196 | 197 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 213 | 214 | 215 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Android JNI获取应用签名 2 | 3 | ### 一.前言: 4 | >移动端数据加密,需要将RSA加密公钥存储,考虑到安全,现将公钥存在.so文件中,为了防止有人将.so文件拷贝使用,因此在里面验证app的签名,对比签名信息,如果正确,返回正确公钥。 5 | 6 | ### 二.参考: 7 | 8 | [Android JNI NDK C++ so本地验证 获取应用签名 9 | ](http://www.jianshu.com/p/289c0b227902?utm_campaign=haruki&utm_content=note&utm_medium=reader_share&utm_source=qq) 10 | 11 | [AndroidStudio 编译C/C++文件生成SO文件](http://blog.csdn.net/krubo1/article/details/50547681) 12 | 13 | [android so 文件存私密数据,且防止 so文件未知应用盗用](http://blog.csdn.net/xx753277/article/details/37567951) 14 | 15 | [Android JNI 获取应用签名](http://blog.csdn.net/masonblog/article/details/28095709) 16 | 17 | [Android通过NDK获取Keystore签名值](http://blog.csdn.net/chenfeng0104/article/details/21641427) 18 | 19 | 20 | ### 三.集成: 21 | 1. 配置ndk环境 22 | 23 | 打开项目中Project Structure,配置ndk目录 24 | 25 | ![示例图片](https://github.com/wxmylife/JNI_SignDemo/blob/master/img/1.png) 26 | 27 | 2. 配置app下的build.gradle 28 | 29 | ![示例图片](https://github.com/wxmylife/JNI_SignDemo/blob/master/img/2.png) 30 | 31 | ![示例图片](https://github.com/wxmylife/JNI_SignDemo/blob/master/img/3.png) 32 | 33 | 3. 修改项目下gradle.properties文件 34 | 35 | 填加如下命令: 36 | 37 | `android.useDeprecatedNdk=true` 38 | 39 | 40 | 4. 调用c++的java类 41 | 42 | **必须与app下的build.gradle中moduleName相同** 43 | 44 | ``` 45 | public class JNIUtils { 46 | 47 | static { 48 | System.loadLibrary("signUtil");//必须与app下的build.gradle中moduleName相同 49 | } 50 | 51 | public static native String getPublicKey(Object obj); 52 | } 53 | ``` 54 | 55 | 5. 生成class文件 56 | 57 | 选择**Build**下的**Make Project** 58 | 59 | ![示例图片](https://github.com/wxmylife/JNI_SignDemo/blob/master/img/4.png) 60 | 61 | ![示例图片](https://github.com/wxmylife/JNI_SignDemo/blob/master/img/7.png) 62 | 63 | 6. 生成头文件 64 | 65 | 进入Android Studio自带的终端中: 66 | 67 | ```cd app/src/main``` 68 | 69 | ![示例图片](https://github.com/wxmylife/JNI_SignDemo/blob/master/img/9.png) 70 | 71 | 通过如下命令生成头文件(Mac): 72 | 73 | ```javah -d jni -classpath /[项目地址]/app/build/intermediates/classes/debug [你的包名+包含native方法的类]``` 74 | 75 | ![示例图片](https://github.com/wxmylife/JNI_SignDemo/blob/master/img/10.png) 76 | 77 | ![示例图片](https://github.com/wxmylife/JNI_SignDemo/blob/master/img/11.png) 78 | 79 | 7. 创建c++文件 80 | 81 | 在jni文件夹下创建一个c++文件,名字可以取任意的 82 | 83 | ![示例图片](https://github.com/wxmylife/JNI_SignDemo/blob/master/img/13.png) 84 | 85 | 实现.h文件 86 | 87 | ``` 88 | 89 | #include 90 | #include 91 | #include 92 | #include "com_wxmylife_jni_JNIUtils.h" //导入.h头文件 93 | 94 | /** 95 | *这个key是和服务器之间通信的秘钥 96 | */ 97 | const char* AUTH_KEY = "keyValue"; 98 | 99 | /** 100 | * 发布的app 签名,只有和本签名一致的app 才会返回 AUTH_KEY 101 | * 这个RELEASE_SIGN的值是上一步用java代码获取的值 102 | */ 103 | const char* RELEASE_SIGN = "308201dd30820146020101300d06092a864886f70d010105050030373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b3009060355040613025553301e170d3136313132353137343333315a170d3436313131383137343333315a30373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b300906035504061302555330819f300d06092a864886f70d010101050003818d0030818902818100c0f7cb6d1cd3af254945c8e784545666ac707b31f754b01a772817ece6e64b58c834ff08cb142b9cf2b1f73ee324c2efa199d5aecb7453573161a538d031c59914af4bb857b3fa36d0a46dc1f03fd130df02f17b67f4731f7333c15035866cbc7a997c2deb90336f39e7191a5826311428de7b1ba8fd948a0aa457223281c0df0203010001300d06092a864886f70d0101050500038181004d8dd7463108247341244ebc4973aaf93b33f8cf9703c4d9be80a368b6f47701f66ece6cb1121014dc1c5b42c49eae86b2a4620286aba1b221ece7fd23dc7329c8486c66a51ab8f127c9adb86944957b159b7b4a5e30b716f48524d0c2c75608532c747c70aca8ffdcaa2bbdb00f6f62f37b939b377460e1a7560101d1280a65"; 104 | 105 | /** 106 | * 发布的app 签名 的HashCode 107 | */ 108 | const int RELEASE_SIGN_HASHCODE = -332752192; 109 | 110 | JNIEXPORT jstring JNICALL Java_com_wxmylife_jni_JNIUtils_getPublicKey 111 | (JNIEnv *env, jclass jclazz, jobject contextObject){ 112 | 113 | jclass native_class = env->GetObjectClass(contextObject); 114 | jmethodID pm_id = env->GetMethodID(native_class, "getPackageManager", "()Landroid/content/pm/PackageManager;"); 115 | jobject pm_obj = env->CallObjectMethod(contextObject, pm_id); 116 | jclass pm_clazz = env->GetObjectClass(pm_obj); 117 | // 得到 getPackageInfo 方法的 ID 118 | jmethodID package_info_id = env->GetMethodID(pm_clazz, "getPackageInfo","(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;"); 119 | jclass native_classs = env->GetObjectClass(contextObject); 120 | jmethodID mId = env->GetMethodID(native_classs, "getPackageName", "()Ljava/lang/String;"); 121 | jstring pkg_str = static_cast(env->CallObjectMethod(contextObject, mId)); 122 | // 获得应用包的信息 123 | jobject pi_obj = env->CallObjectMethod(pm_obj, package_info_id, pkg_str, 64); 124 | // 获得 PackageInfo 类 125 | jclass pi_clazz = env->GetObjectClass(pi_obj); 126 | // 获得签名数组属性的 ID 127 | jfieldID signatures_fieldId = env->GetFieldID(pi_clazz, "signatures", "[Landroid/content/pm/Signature;"); 128 | jobject signatures_obj = env->GetObjectField(pi_obj, signatures_fieldId); 129 | jobjectArray signaturesArray = (jobjectArray)signatures_obj; 130 | jsize size = env->GetArrayLength(signaturesArray); 131 | jobject signature_obj = env->GetObjectArrayElement(signaturesArray, 0); 132 | jclass signature_clazz = env->GetObjectClass(signature_obj); 133 | 134 | //第一种方式--检查签名字符串的方式 135 | jmethodID string_id = env->GetMethodID(signature_clazz, "toCharsString", "()Ljava/lang/String;"); 136 | jstring str = static_cast(env->CallObjectMethod(signature_obj, string_id)); 137 | char *c_msg = (char*)env->GetStringUTFChars(str,0); 138 | 139 | if(strcmp(c_msg,RELEASE_SIGN)==0)//签名一致 返回合法的 api key,否则返回错误 140 | { 141 | return (env)->NewStringUTF(AUTH_KEY); 142 | }else 143 | { 144 | return (env)->NewStringUTF("error"); 145 | } 146 | 147 | //第二种方式--检查签名的hashCode的方式 148 | /* 149 | jmethodID int_hashcode = env->GetMethodID(signature_clazz, "hashCode", "()I"); 150 | jint hashCode = env->CallIntMethod(signature_obj, int_hashcode); 151 | if(hashCode == RELEASE_SIGN_HASHCODE) 152 | { 153 | return (env)->NewStringUTF(AUTH_KEY); 154 | }else{ 155 | return (env)->NewStringUTF("错误"); 156 | } 157 | */ 158 | 159 | } 160 | ``` 161 | 162 | 8. java相关代码 163 | 164 | >获取App签名 165 | 166 | ``` 167 | public static String getSignature(Context context) 168 | { 169 | try { 170 | /** 通过包管理器获得指定包名包含签名的包信息 **/ 171 | PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES); 172 | /******* 通过返回的包信息获得签名数组 *******/ 173 | Signature[] signatures = packageInfo.signatures; 174 | /******* 循环遍历签名数组拼接应用签名 *******/ 175 | return signatures[0].toCharsString(); 176 | /************** 得到应用签名 **************/ 177 | } catch (PackageManager.NameNotFoundException e) { 178 | e.printStackTrace(); 179 | } 180 | return null; 181 | } 182 | ``` 183 | 184 | 9. 完成效果 185 | 186 | | 成功 | 失败 | 187 | | :--------: | :--------:| 188 | | ![示例图片](https://github.com/wxmylife/JNI_SignDemo/blob/master/gif/b.gif) | ![示例图片](https://github.com/wxmylife/JNI_SignDemo/blob/master/gif/a.gif) | 189 | 190 | 191 | 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.1" 6 | defaultConfig { 7 | applicationId "com.wxmylife.jni" 8 | minSdkVersion 16 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | 13 | ndk { 14 | moduleName "signUtil" //生成的.so文件 15 | abiFilters "armeabi", "armeabi-v7a", "x86" //定要ndk需要兼容的架构 16 | } 17 | } 18 | 19 | 20 | sourceSets { 21 | main { 22 | jni.srcDirs = ['src/main/jni', 'src/main/jni/'] 23 | } 24 | } 25 | 26 | buildTypes { 27 | release { 28 | minifyEnabled false 29 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 30 | } 31 | } 32 | } 33 | 34 | dependencies { 35 | compile fileTree(dir: 'libs', include: ['*.jar']) 36 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 37 | exclude group: 'com.android.support', module: 'support-annotations' 38 | }) 39 | compile 'com.android.support:appcompat-v7:25.1.1' 40 | testCompile 'junit:junit:4.12' 41 | } 42 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/wxmylife/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/wxmylife/jni/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.wxmylife.jni; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.wxmylife.jni", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/wxmylife/jni/JNIUtils.java: -------------------------------------------------------------------------------- 1 | package com.wxmylife.jni; 2 | 3 | /** 4 | * Created by wxmylife on 2017/3/7. 5 | */ 6 | 7 | public class JNIUtils { 8 | 9 | static { 10 | System.loadLibrary("signUtil"); 11 | } 12 | 13 | public static native String getPublicKey(Object obj); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/wxmylife/jni/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.wxmylife.jni; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | import android.content.pm.Signature; 7 | import android.os.Bundle; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.view.View; 10 | import android.widget.TextView; 11 | 12 | public class MainActivity extends AppCompatActivity { 13 | 14 | private static final String TAG = MainActivity.class.getSimpleName(); 15 | 16 | private String publicKey; 17 | 18 | @Override 19 | protected void onCreate(Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | setContentView(R.layout.activity_main); 22 | findViewById(R.id.btn_sign).setOnClickListener(new View.OnClickListener() { 23 | @Override public void onClick(View view) { 24 | publicKey= JNIUtils.getPublicKey(MainActivity.this); 25 | ((TextView)findViewById(R.id.txt_key)).setText(publicKey); 26 | } 27 | }); 28 | 29 | 30 | 31 | // String debugSign=getSignature(this); 32 | // if (!TextUtils.isEmpty(debugSign)){ 33 | // Log.e(TAG,"debug签名为------>>>"+debugSign); 34 | // } 35 | 36 | } 37 | 38 | 39 | public static String getSignature(Context context) 40 | { 41 | try { 42 | /** 通过包管理器获得指定包名包含签名的包信息 **/ 43 | PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES); 44 | /******* 通过返回的包信息获得签名数组 *******/ 45 | Signature[] signatures = packageInfo.signatures; 46 | /******* 循环遍历签名数组拼接应用签名 *******/ 47 | return signatures[0].toCharsString(); 48 | /************** 得到应用签名 **************/ 49 | } catch (PackageManager.NameNotFoundException e) { 50 | e.printStackTrace(); 51 | } 52 | return null; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/jni/com_wxmylife_jni_JNIUtils.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class com_wxmylife_jni_JNIUtils */ 4 | 5 | #ifndef _Included_com_wxmylife_jni_JNIUtils 6 | #define _Included_com_wxmylife_jni_JNIUtils 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: com_wxmylife_jni_JNIUtils 12 | * Method: getPublicKey 13 | * Signature: (Ljava/lang/Object;)Ljava/lang/String; 14 | */ 15 | JNIEXPORT jstring JNICALL Java_com_wxmylife_jni_JNIUtils_getPublicKey 16 | (JNIEnv *, jclass, jobject); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | #endif 22 | -------------------------------------------------------------------------------- /app/src/main/jni/sign.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by wxmylife on 2017/3/7. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include "com_wxmylife_jni_JNIUtils.h" //导入.h头文件 9 | 10 | /** 11 | *这个key是和服务器之间通信的秘钥 12 | */ 13 | const char* AUTH_KEY = "keyValue"; 14 | 15 | /** 16 | * 发布的app 签名,只有和本签名一致的app 才会返回 AUTH_KEY 17 | * 这个RELEASE_SIGN的值是上一步用java代码获取的值 18 | */ 19 | const char* RELEASE_SIGN = "308201dd30820146020101300d06092a864886f70d010105050030373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b3009060355040613025553301e170d3136313132353137343333315a170d3436313131383137343333315a30373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b300906035504061302555330819f300d06092a864886f70d010101050003818d0030818902818100c0f7cb6d1cd3af254945c8e784545666ac707b31f754b01a772817ece6e64b58c834ff08cb142b9cf2b1f73ee324c2efa199d5aecb7453573161a538d031c59914af4bb857b3fa36d0a46dc1f03fd130df02f17b67f4731f7333c15035866cbc7a997c2deb90336f39e7191a5826311428de7b1ba8fd948a0aa457223281c0df0203010001300d06092a864886f70d0101050500038181004d8dd7463108247341244ebc4973aaf93b33f8cf9703c4d9be80a368b6f47701f66ece6cb1121014dc1c5b42c49eae86b2a4620286aba1b221ece7fd23dc7329c8486c66a51ab8f127c9adb86944957b159b7b4a5e30b716f48524d0c2c75608532c747c70aca8ffdcaa2bbdb00f6f62f37b939b377460e1a7560101d1280a65"; 20 | 21 | /** 22 | * 发布的app 签名 的HashCode 23 | */ 24 | const int RELEASE_SIGN_HASHCODE = -332752192; 25 | 26 | JNIEXPORT jstring JNICALL Java_com_wxmylife_jni_JNIUtils_getPublicKey 27 | (JNIEnv *env, jclass jclazz, jobject contextObject){ 28 | 29 | jclass native_class = env->GetObjectClass(contextObject); 30 | jmethodID pm_id = env->GetMethodID(native_class, "getPackageManager", "()Landroid/content/pm/PackageManager;"); 31 | jobject pm_obj = env->CallObjectMethod(contextObject, pm_id); 32 | jclass pm_clazz = env->GetObjectClass(pm_obj); 33 | // 得到 getPackageInfo 方法的 ID 34 | jmethodID package_info_id = env->GetMethodID(pm_clazz, "getPackageInfo","(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;"); 35 | jclass native_classs = env->GetObjectClass(contextObject); 36 | jmethodID mId = env->GetMethodID(native_classs, "getPackageName", "()Ljava/lang/String;"); 37 | jstring pkg_str = static_cast(env->CallObjectMethod(contextObject, mId)); 38 | // 获得应用包的信息 39 | jobject pi_obj = env->CallObjectMethod(pm_obj, package_info_id, pkg_str, 64); 40 | // 获得 PackageInfo 类 41 | jclass pi_clazz = env->GetObjectClass(pi_obj); 42 | // 获得签名数组属性的 ID 43 | jfieldID signatures_fieldId = env->GetFieldID(pi_clazz, "signatures", "[Landroid/content/pm/Signature;"); 44 | jobject signatures_obj = env->GetObjectField(pi_obj, signatures_fieldId); 45 | jobjectArray signaturesArray = (jobjectArray)signatures_obj; 46 | jsize size = env->GetArrayLength(signaturesArray); 47 | jobject signature_obj = env->GetObjectArrayElement(signaturesArray, 0); 48 | jclass signature_clazz = env->GetObjectClass(signature_obj); 49 | 50 | //第一种方式--检查签名字符串的方式 51 | jmethodID string_id = env->GetMethodID(signature_clazz, "toCharsString", "()Ljava/lang/String;"); 52 | jstring str = static_cast(env->CallObjectMethod(signature_obj, string_id)); 53 | char *c_msg = (char*)env->GetStringUTFChars(str,0); 54 | 55 | if(strcmp(c_msg,RELEASE_SIGN)==0)//签名一致 返回合法的 api key,否则返回错误 56 | { 57 | return (env)->NewStringUTF(AUTH_KEY); 58 | }else 59 | { 60 | return (env)->NewStringUTF("error"); 61 | } 62 | 63 | //第二种方式--检查签名的hashCode的方式 64 | /* 65 | jmethodID int_hashcode = env->GetMethodID(signature_clazz, "hashCode", "()I"); 66 | jint hashCode = env->CallIntMethod(signature_obj, int_hashcode); 67 | if(hashCode == RELEASE_SIGN_HASHCODE) 68 | { 69 | return (env)->NewStringUTF(AUTH_KEY); 70 | }else{ 71 | return (env)->NewStringUTF("错误"); 72 | } 73 | */ 74 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 |