android studio JNI/NDK的简单使用

最近更新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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值