您的位置:首页 > 移动开发 > Android开发

Android JNI模板与读取系统属性笔记

2018-01-02 16:17 399 查看

一、编写目的

本文主要提供一个简单可用的 jni 模板,便于在APK中编写native代码。通过记录,希望能对jni学习有一个更深的认识。


二、APP中的jni模板

1、jni文件在项目中的截图



2、详细步骤

1)、在src/main/ 层,创建jni目录用于存放,native代码

2)、增加Android.mk

# Android.mk for check is rightful board

LOCAL_PATH := $(call my-dir)

# Program
include $(CLEAR_VARS)
LOCAL_MODULE := nativeXXXX
LOCAL_SRC_FILES := nativeXXXX.c
LOCAL_C_INCLUDES += $(LOCAL_PATH)    // 配置头文件目录,根据实际修改
LOCAL_LDLIBS := -llog -lz    // 添加静态依赖库,编译需要
LOCAL_SHARED_LIBRARIES := libcutils    // 添加动态依赖库,读取系统属性需要
include $(BUILD_SHARED_LIBRARY)


3)、增加Application.mk

APP_ABI :=armeabi-v7a     // 指定编译哪些CPU架构


4)、增加nativeXXXX.c

//
// Created by LinChengChun on 2018/1/2.
//

#include "nativeXXXX.h"

static const char *ClassName = "com/example/XXXX"; // 包名

jint test(JNIEnv *env, jobject jobj){
char *key = "ro.build.id";
char value[PROP_VALUE_MAX] = {0};
int ret = __system_property_get(key, value);
if(ret <= 0 ){
return -1;
}

ret = strcmp(value, "XXXX");
if(ret != 0){
return -1;
}

return 0;
}

static JNINativeMethod METHODS[]={
{"test","()I",(void *)test}
};

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
int retVal = -1;
JNIEnv *env;
if ( (*vm)->GetEnv(vm,(void **) &env, JNI_VERSION_1_4) == JNI_OK  ) {
jclass clazz = (*env)->FindClass(env,ClassName);
if (clazz != NULL) {
if ((*env)->RegisterNatives(env,clazz, METHODS,sizeof(METHODS) / sizeof(METHODS[0])) >= 0) {
retVal = JNI_VERSION_1_4;
}else{
LOGI("RegisterNatives Subprocess.create method failed!");
}
(*env)->DeleteLocalRef(env,clazz);
}else{
LOGI("className not found!");
}
}
return retVal;
}

JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved)
{
}


5)、增加nativeXXXX.h

//
// Created by LinChengChun on 2018/1/2.
//

#ifndef XXXX_ANDROID_NATIVEXXXX_H
#define XXXX_ANDROID_NATIVEXXXX_H

#include <jni.h>
#include <assert.h>
#include <string.h>
#include <sys/types.h>
#include <android/log.h>
#include <sys/system_properties.h>

#define LOG_TAG "NativeXXXX"
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))

#endif //XXXX_ANDROID_NATIVEXXXX_H


6)、在JAVA层增加native接口类

package com.example;

/**
* Created by LinChengChun on 2018/1/2.
*/

public class XXXX{

public native static int test();     // 在外部可以通过 XXXX.test() 方法调用

static {
System.loadLibrary("nativeXXXX");  // 优先加载动态库
}
}


3、添加NDK编译工具,AndroidStudio中添加 外部编译命令 的方法

在Settings > Tools > External Tools中添加命令行工具(NDK)如下: ndk-build、ndk build clean、javah







如果顺利完成以上步骤,就可以在工程任意位置 右键->NDK->ndk-build 编译生成 so库了

三、在JNI读取系统属性方法

用 objdump 看了一下 libc.so ,找到了其中的函数。如下:

000095f0 g    F .text  00000014 __system_properties_init
00009604 g    F .text  00000014 __system_property_find
00009618 g    F .text  00000014 __system_property_find_nth
0000962c g    F .text  00000014 __system_property_get
00009640 g    F .text  00000014 __system_property_read
00009654 g    F .text  00000014 __system_property_wait


头文件是 system_properties.h ,在 usr/include/sys目录下面。

__system_property_get 可以用来获取一个属性值,函数原型如下:

/* Look up a system property by name, copying its value and a
** \0 terminator to the provided pointer.  The total bytes
** copied will be no greater than PROP_VALUE_MAX.  Returns
** the string length of the value.  A property that is not
** defined is identical to a property with a length 0 value.
*/
int __system_property_get(const char *name, char *value);


读写ro.build.id的方法

char *key = "ro.build.id";
char value[PROP_VALUE_MAX] = {0};
int ret = __system_property_get(key, value);
if(ret <= 0 ){
return -1;
}


四、在JAVA中读取系统属性方法

private static String getSystemProperty(String key, String defaultValue) {
try {
Class<?> clz = Class.forName("android.os.SystemProperties"); // 通过反射实现
Method get = clz.getMethod("get", String.class, String.class);
return (String)get.invoke(clz, key, defaultValue);
} catch (Exception e) {
}
return defaultValue;
}

public static  boolean test(){
String value =CurrentClass.getSystemProperty("ro.build.id", null);
if (TextUtils.isEmpty(value)){
return false;
}
if(!"XXXX".equals(value)){
return false;
}

return true;
}


五、把编译生成的so库打包到apk里面去

android {
compileSdkVersion 23
buildToolsVersion '25.0.0'

defaultConfig {
。。。。。。

ndk {
abiFilters 'armeabi-v7a', 'x86'
}

//加载so库目录
sourceSets {
main {
// Tell Android Gradle that no jni code need to compile, so we can avoid Ndk compile task,
// then we will to compile use ndk-build in command-line.
jni.srcDirs = []    // 不依赖 gradle来编译 jni,根据我们的ndk-build来编译
jniLibs.srcDir "src/main/libs"
}
}
}
。。。。。。


六、以上是APP 添加 jni 代码的全部记录,注意下包名,一般可以启动运行正常,jni基础知识会在另外文章介绍。^-^

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  native jni apk