Android JNI输出LOG

从一个论坛转来的

 

这个程序使用eclipse创建一个java程序,通过jni调用我们的共享库,这个共享库非常简单,只实现一个写日志的函数,ok,我们开始。
首先,我们还是先建立一个Android工程,打开Eclipse开发环境,新建工程,Build Target设为Android 1.5, 其他项目随便填。为了方便,可以把这个项目放在ndk的apps目录下面。
其次,我们新建一个调用共享库的类,名字就叫MyLog好了,给他添加一个静态区块,以实现加载共享库的目的。如下所示:
static
{
  try
  {
   System.loadLibrary("TestLog");
  }
  catch (UnsatisfiedLinkError e)
  {
   System.err.println("Cannot load hello library:/n " + e.toString());
  }
}

然后,再添加一个native方法:
public native int Log();

然后编译,使用javah生成一个jni样式头文件,如下所示,
javah -jni -d D:/eclipse/workspace/TestLog/bin -classpath D:/eclipse/workspace/TestLog/bin testLog.myLog.MyLog
请将上面的D:/eclipse/workspace/TestLog/bin换成你的类文件路径, 注意,这里要使用全限定类型名称。

我们在主界面上添加一个按钮,在主Activity类的onCreate方法里面,为这个按钮添加一个事件接口,如下所示,

Button btnLog = (Button) findViewById(R.id.btnLog);
btnLog.setOnClickListener(new OnClickListener()
{
   @Override
   public void onClick(View v)
   {     
      MyLog log = new MyLog();
      log.Log();  
   }      
});

在项目目录下面添加一个Application.mk文件,文件内容很简单,只有两句话,
APP_PROJECT_PATH := $(call my-dir)
APP_MODULES      := TestLog
这样,我们的java工程就做好了,接下来我们再来写native c的共享库,在ndk/sources目录下新建一个子目录,名字就叫TestLog好了,
把刚才生成的jni头文件拷贝到这里,然后新建一个.c文件,这个文件只有一个函数,如下所示:
#include <log.h>
#include "testLog_myLog_MyLog.h"
JNIEXPORT jint JNICALL Java_testLog_myLog_MyLog_Log(JNIEnv * penv, jobject obj)
{
   static int iCount = 0;
   iCount++;
   __android_log_print(ANDROID_LOG_INFO, "wuzhenhua", "hello, this is my number %d log message!", iCount);
   return 0;
}
注意,函数声明必须要跟生成的jni头文件保持一致,否则java会找不到要调用的函数,导致异常发生!
这个函数内部调用了 __android_log_print这个API函数,向系统输出日志,第一个参数指定日志类型级别,声明为android_LogPriority枚举类型,如下所示:
typedef enum android_LogPriority {
    ANDROID_LOG_UNKNOWN = 0,
    ANDROID_LOG_DEFAULT,   
    ANDROID_LOG_VERBOSE,
    ANDROID_LOG_DEBUG,
    ANDROID_LOG_INFO,
    ANDROID_LOG_WARN,
    ANDROID_LOG_ERROR,
    ANDROID_LOG_FATAL,
    ANDROID_LOG_SILENT,  
} android_LogPriority;
第二参数,是一个标签,名字随便取,只是起到一个分类和过滤的作用。
第三个参数,就是具体的消息文本了,注意,这个函数取不定长度参数,让你可以象用printf函数那样使用,也就是这个参数可以加上类似%d,%x等格式化字串,在这个参数后面再加上相应类型的参数即可。
好,主函数写完了,我们再来写一个Android.mk文件,以下是文件内容:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := TestLog
LOCAL_SRC_FILES := TestLog.c
LOCAL_LDLIBS += -llog

include $(BUILD_SHARED_LIBRARY)
ok,就差最后一步,我们来编译一下,进入到ndk主目录,输入命令:
make APP=TestLog
大功告成!生成的共享库会自动拷贝到  你的项目路径/libs/armeabi目录下面。

### 使用JNIAndroid中生成或使用.so库 为了使应用程序能够调用本地方法,在`app/src/main/jniLibs/`目录下放置`.so`文件是一个常见做法[^1]。当涉及到创建这些共享库时,开发者通常会编写C/C++代码并利用NDK构建工具链来编译它们。 对于希望集成现有原生代码的情况,可以按照如下方式操作: #### 准备工作环境 确保已安装Android NDK,并配置好开发环境中相应的路径变量以便于命令行工具访问。 #### 编写C/C++源码 定义想要暴露给Java层的方法接口,例如在一个名为`native-lib.cpp`的文件里实现逻辑功能。 ```cpp #include <jni.h> #include <string> extern "C" JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_stringFromJNI(JNIEnv *env, jobject /* this */) { std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); } ``` 此段代码展示了如何声明一个简单的函数用于返回字符串至Java端。 #### 构建脚本设置(CMakeLists.txt 或 Android.mk) 如果采用CMake作为构建系统,则需编辑项目中的`CMakeLists.txt`文件以指定输入源文件以及链接必要的静态库,像这样: ```cmake add_library(native-lib SHARED src/main/cpp/native-lib.cpp) find_library(log-lib log) target_link_libraries(native-lib ${log-lib}) ``` 上述片段说明了怎样添加一个新的共享库(`SHARED`)目标,并将其与日志记录器连接起来。 另外一种情况是基于`ndk-build`体系结构下的`Android.mk`文件可能看起来像是这样的: ```makefile LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := app-glue LOCAL_SRC_FILES := ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := native-lib LOCAL_SRC_FILES := src/main/cpp/native-lib.cpp LOCAL_STATIC_LIBRARIES := app-glue LOCAL_LDLIBS += -llog include $(BUILD_SHARED_LIBRARY) ``` 这里不仅包含了自定义模块还加入了来自NDK自带的支持包(如`android_native_app_glue`),并且指定了要链接的日志库。 #### 加载SO库并在Java侧调用 最后一步是在应用启动期间加载所需的动态链接库,这可以通过修改活动类(比如`MainActivity.java`)完成初始化过程: ```java static{ System.loadLibrary("native-lib"); } public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tv = findViewById(R.id.sample_text); tv.setText(stringFromJNI()); // 调用了由C++实现的方法 } public native String stringFromJNI(); } ``` 这段Java代码实现了对之前提到过的本地方法的实际调用,并将结果显示到界面上。 通过以上步骤就可以成功地在Android平台上运用JNI技术来生成和使用`.so`形式的原生库了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值