最近更新android sdk26(8.0)时看到
NDK 15.2.4203891
于是就更新了,没想到直接就把D盘干满了,只能删掉D盘一些文件了,其中包括android-ndk-r13b文件。
顺便再运行一遍记录下吧,虽然接触JNI开发的机会不多,但是偶尔有涉及,比如我们把登录的AES秘钥放到了jni里,提高了安全性,比较破解so文件比java难度高些。
1、环境配置
除了更新上文提到的NDK,还需要CMake , LLDB
2、创建需要被java调用的java文件—JNIUtil
public class NdkJniUtils {
public native String getUserKey(String signature);
public native String getWeixinAppKey(String signature);
}
之后在别处直接调用,下面是一个使用的案例:
NdkJniUtils util = new NdkJniUtils();
util.getUserKey(PackageUtil.getSignature(this)); //此出输入包值
==================
public class PackageUtil {
public static String getSignature(Context context)
{
try {
/** 通过包管理器获得指定包名包含签名的包信息 **/
PackageInfo packageInfo = null;
try {
packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
/******* 通过返回的包信息获得签名数组 *******/
Signature[] signatures = packageInfo.signatures;
/******* 循环遍历签名数组拼接应用签名 *******/
return signatures[0].toCharsString();
/************** 得到应用签名 **************/
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
3、编辑c文件
然后build project得到其中中间文件,我们关注的是.class文件。编译OK以后生成的class文件在AS工程的如下目录:
NDKApplication\app\build\intermediates\classes\debug
然后接下来的步骤就是根据生成的class文件,利用javah生成对应的 .h头文件。
点开AS的Terminal标签,默认进入到该项目的app文件夹下。我在windows平台下输入如下命令跳转到class中间文件生成路径:
xxxxx\app> cd build\intermediates\classes\debug
然后执行如下javah命令生成h文件:
xxxxx\debug> javah -jni com.xxx.cn.utility.secure.NdkJniUtils
执行完之后你可以在文件夹NDKApplication\app\build\intermediates\classes\debug下看见生成的 .h头文件为:
xxx_NdkJniUtils.h
其内容为:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_xxx_cn_utility_secure_NdkJniUtils */
#ifndef _Included_com_xxx_cn_utility_secure_NdkJniUtils
#define _Included_com_xxx_cn_utility_secure_NdkJniUtils
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_xxx_cn_utility_secure_NdkJniUtils
* Method: getUserKey
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_xxx_cn_utility_secure_NdkJniUtils_getUserKey
(JNIEnv *, jobject, jstring);
/*
* Class: com_xxx_cn_utility_secure_NdkJniUtils
* Method: getWeixinAppKey
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_xxx_cn_utility_secure_NdkJniUtils_getWeixinAppKey
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
在工程的main目录下新建一个名字为jni的目录,然后将刚才的 .h文件剪切过来。在jni目录下新建一个cpp文件,随意取名,我的叫jniUtil.cpp 。然后编辑代码如下:
#include "com_xxx_cn_utility_secure_NdkJniUtils.h"
#include <string.h>
//http api 授权 key ,由服务端提供
const char* WEIXIN_APP_SECRET = "xxx";
//用户aes加解密秘钥
const char* USER_KEY = "aaa";
//发布的app 签名,只有和本签名一致的app 才会返回合法的 授权 key,防止so文件被未知应用盗用
const char* RELEASE_SIGN ="xxx";
JNIEXPORT jstring JNICALL Java_com_xxx_cn_utility_secure_NdkJniUtils_getWeixinAppKey
(JNIEnv* env, jobject obj, jstring signStrng) {
const char *str = (env)->GetStringUTFChars(signStrng, 0);
int ret=strcmp(str,RELEASE_SIGN);
env->ReleaseStringUTFChars(signStrng, str);
return ret==0?(env)->NewStringUTF(WEIXIN_APP_SECRET):(env)->NewStringUTF("");
}
JNIEXPORT jstring JNICALL Java_com_xxx_cn_utility_secure_NdkJniUtils_getUserKey
(JNIEnv* env, jobject obj, jstring signStrng) {
const char *str = (env)->GetStringUTFChars(signStrng, 0);
int ret=strcmp(str,RELEASE_SIGN);
env->ReleaseStringUTFChars(signStrng, str);
return ret==0?(env)->NewStringUTF(USER_KEY):(env)->NewStringUTF("");
}
接下来在工程的local.properties文件中添加NDK路径(上面下载好的那个NDK),类似其中的SDK路径一样:
ndk.dir=D\:\\Android\\Android\\sdk\\ndk-bundle
sdk.dir=D\:\\Android\\Android\\sdk
接下来在app module目录下的build.gradle中设置库文件名(生成的so文件名)。找到gradle文件的defaultConfig这项,在里面添加如下内容:
defaultConfig {
......
ndk{
moduleName "JniUtil" //生成的so名字,和NdkJniUtils里的名字一样
abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库。目前可有可无。
}
}
现在生成的so库名字也有了,那就去代码的NdkJniUtils java文件添加静态初始化load代码,添加如下:
public class JniUtil {
public native String getUserKey(String signature);
public native String getWeixinAppKey(String signature);
static {
System.loadLibrary("JniUtil");
}
}
好了,到此AS下NDK JNI开发的代码编写和设置就OK了,接下来就是编译工程运行就可以了:
运行,我去出错了:
Error:Execution failed for task ':libtermexec:compileReleaseNdk'.
> Error: Your project contains C++ files but it is not using a supported native build system.
Consider using CMake or ndk-build integration with the stable Android Gradle plugin:
https://developer.android.com/studio/projects/add-native-code.html
or use the experimental plugin:
https://developer.android.com/studio/build/experimental-plugin.html.
需要在工程下gradle.properties添加:
android.useDeprecatedNdk=true