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)

# 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基础知识会在另外文章介绍。^-^

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值