NDK 的一点简单应用

在这里记录一下某些内容。
在安卓app里面通过jni执行某些东西,再传回java层来。
比如这样一个简单的小文件

// NdkTools.java
package com.example.jnitest;

public class NdkTools {
    public static native String getProp(String key,String def);

    static {
        System.loadLibrary("ndktools");
    }
}

通过native关键字指定这个函数通过jni执行的,下面的 System.loadLibrary 载入 ndktools 这个so。

在app的 res 同级目录新建jni文件夹,我们用的jni相关的文件就放在这里了。

.
├── ./AndroidManifest.xml
├── ./java
│   └── ./java/com
│       └── ./java/com/example
│           └── ./java/com/example/jnitest
│               ├── ./java/com/example/jnitest/MainActivity.java
│               └── ./java/com/example/jnitest/NdkTools.java
├── ./jni
│   ├── ./jni/Android.mk
│   ├── ./jni/NdkTools.c
│   └── ./jni/NdkTools.h
└── ./res
    ├── ./res/drawable
     xxxxx

NDKTools.h 是在 java 目录里面执行 javah -jni com.example.jnitest.NdkTools 生成出来的。

在模块的 build.gradle 的 android 段内添加

    externalNativeBuild {
        ndkBuild {
            path file('src/main/jni/Android.mk')
        }
    }

这样编译的时候就会通过指定的Android.mk去编译相应的so出来了。
Android.mk内容如下

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := ndktools

LOCAL_SRC_FILES := NdkTools.c

LOCAL_LDLIBS +=-L$(SYSROOT)/usr/lib -lm -llog

include $(BUILD_SHARED_LIBRARY)

这个稍微了解一下Android.mk的语法规则就行了。
NdkTools.h内容如下

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <android/log.h>
#include <sys/system_properties.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/* Header for class com_example_jnitest_NdkTools */

#ifndef _Included_com_example_jnitest_NdkTools
#define _Included_com_example_jnitest_NdkTools


#define TAG "jni"
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#define LOGV(fmt,args...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, "%s(%d):%s() " fmt,__FILENAME__,__LINE__,__func__,##args)
#define LOGD(fmt,args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, "%s(%d):%s() " fmt,__FILENAME__,__LINE__,__func__,##args)
#define LOGW(fmt,args...) __android_log_print(ANDROID_LOG_WARN, TAG, "%s(%d):%s() " fmt,__FILENAME__,__LINE__,__func__,##args)
#define LOGE(fmt,args...) __android_log_print(ANDROID_LOG_ERROR, TAG, "%s(%d):%s() " fmt,__FILENAME__,__LINE__,__func__,##args)
#define LOGI(fmt,args...) __android_log_print(ANDROID_LOG_INFO, TAG, "%s(%d):%s() " fmt,__FILENAME__,__LINE__,__func__,##args)

#define property_get(...) __system_property_get(__VA_ARGS__)
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_jnitest_NdkTools
 * Method:    getProp
 * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_jnitest_NdkTools_getProp
  (JNIEnv *, jclass, jstring, jstring);

#ifdef __cplusplus
}
#endif
#endif

这里用宏定义重新简化了一下在c文件内调用安卓的LOG和系统属性获取的函数
NdkTools.c内容如下

#include "NdkTools.h"
JNIEXPORT jstring JNICALL Java_com_example_jnitest_NdkTools_getProp
  (JNIEnv *env, jclass obj, jstring key, jstring def)
{
    const char *lkey=(*env)->GetStringUTFChars(env,key,0);
    LOGI("search property %s",lkey);
    char value[81];
    memset(value,0,81);
    int len = property_get(lkey,value);
    if(len==0)
    {
        return def;
    }
    else
    {
        return (*env)->NewStringUTF(env,value);
    }
}

上面透露出这几个内容

  1. 安卓的property最长应该是80个字符,这里可以从aosp的源码看出来
  2. jstring 转 char 可以用形如 const char *lkey=(*env)->GetStringUTFChars(env,key,0);的语句来进行。
posted @ 2020-11-15 12:25  SupperMary  阅读(195)  评论(0编辑  收藏  举报