写点什么

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

用户头像
Changing Lin
关注
发布于: 2021 年 01 月 28 日
Android JNI模板与读取系统属性笔记

一、编写目的


本文主要提供一个简单可用的 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)
# Programinclude $(CLEAR_VARS)LOCAL_MODULE := nativeXXXXLOCAL_SRC_FILES := nativeXXXX.cLOCAL_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 目录下面。

_systemproperty_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 代码的全部记录,注意下包名,一般可以启动运行正常。另外,借助 Android Studio 开发工具提供很便利的创建工程的入口,可以快速的开展 jni 开发。^-^


发布于: 2021 年 01 月 28 日阅读数: 24
用户头像

Changing Lin

关注

获得机遇的手段远超于固有常规之上~ 2020.04.29 加入

我能做的,就是调整好自己的精神状态,以最佳的面貌去面对那些未曾经历过得事情,对生活充满热情和希望。

评论

发布
暂无评论
Android JNI模板与读取系统属性笔记