Android jni 应用初探 (MAC 环境)

来源:互联网 发布:c语言for是什么意思 编辑:程序博客网 时间:2024/06/03 03:51
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">Android JNI HEllOWORD 初探</span>

目标:自己生成so库并进行调用。
**************************
环境:
Mac 10.10.3
Android studio 1.2
NDK (这个不用说,一定要有,,ndk-build 一下包中自带的example,看是否配置好)


**************************
经过作者实践之后总结出的流程:
(1)得到.c 文件
    1.首先要写一个java文件,在java文件中加载so库,并调用native方法。
    2.执行$javah 包命.文件名 生成.h文件(执行此命令应在包命最外层的同级目录)
    3.在新建的.c文件中,include<.h文件>中的方法,并实现。
(2)建立目录结构:在项目的根目录下新建JNI 目录,JNI中放置.c文件、mk文件。
(3)mk文件内容(Android.mk,Application.mk)
    Android.mk文件是用来定义编译规则的文件,描述了编译选项、头文件、源文件、依赖库等。文件用到的主要字段及含义有:
      LOCAL_PATH := $(call my-dir)
      *local_path 定义了本地源码路径  指定调用my-dir


      include $(CLEAR_VARS)
      *清除掉系统的宏定义


     LOCAL_MODULE    := hello-jni
     *指定模块的名字,源文件生成的文件名,若生成so文件则在生成的文件前面会自动加上lib。(这个字段的值 也就是在java中加载的so库的名字)
     LOCAL_SRC_FILES := hello-jni.c
     *指定的C/C++源文件


     include $(BUILD_SHARED_LIBRARY)
     *指定生成的文件类型(BUILD_EXECUTABLE 表示生成可执行文件、)(BUILD_SHARED_LIBRARY 生成动态库)(BUILD_STATIC_LIBRARY 生成静态库)
    Application.mkm描述原生程序的特性


(4)编译:在项目的根目录下执行ndk—build。
         if(在Android studio环境中)
           {
             在main 目录下新建 jniLibs,
             将libs 中生成的内容 全部拷贝到jniLibs目录中
           }
  ***************************
  java 调用c/c++,会根据自身的包名,到特定的文件中去找特定的方法。例如:


  package com.a.b;
  class c
  {
  public static native String MethodName();
  public static void main(String[] args)
  {
  System.loadlibrary("Jni-test");
  MethodName();
  }


  }
  上面这段程序执行时,便会到特定的so库中寻找Java_com_a_b_c_MethodName( JNIEnv* env,
                                                  jobject thiz)
  如果在c文件中这么长的方法名自己去写 避免不了麻烦和出错,有没有方便的方法?
  有就是第一步,利用Javah 生成.h文件,然后把其中的方法拷贝到 实现的c文件就可以了。


  ***************************

  实践Part:

1.新建android应用JniTest(一路next),然后在根目录(JniTest)下新建jni 文件夹,以备后用



2.修改MainActivity内容

public native String getStringFromNative();    private TextView tv;    @Override    protected void onCreate(Bundle savedInstanceState) {        System.loadLibrary("hello");        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        tv=(TextView)findViewById(R.id.tv_word);        tv.setText(getStringFromNative());        Log.i("HelloFromJni----->",getStringFromNative());    }


  public native String getStringFromeNative(),声明了getStringFromeNative()这个Native方法

3.生成.c

(1)$cd 到项目目录,这个可以直接在AndroidStudio中直接选择terminal。


(2 )cd 到新建的jni目录 执行下面的命令:

         $ javah -classpath ../app/src/main/java/ com.example.apple.jnitest.MainActivity

        com.example.apple.jnitest.MainActivity 应当替换成你的java文件的 包命.类名。执行完这句话后,会在新建的jni目录下生成com_example_apple_jnitest_MainActivity.h文件。

        -classpath 后面跟的路径名 应当是从当前文件夹出发,能够找到你的包做外层的目录的路径。既我的目录结构是/app/src/main/java/com/example/apple/jnitest/MainActivity.java,我的classpath只要能找到com 即可。

(3)编写.c

        这个可以把(2)生成的.h  import,然后实现方法就好。我是直接把google给的ndk包example中的代码拷贝修改了。

        .h 文件内容:

            

hello.c 文件代码:

#include<string.h>#include<jni.h>#include<com_example_apple_jnitest_MainActivity.h>jstring JNICALL Java_com_example_apple_jnitest_MainActivity_getStringFromNative  (JNIEnv* env , jobject thiz){#if defined(__arm__)  #if defined(__ARM_ARCH_7A__)    #if defined(__ARM_NEON__)      #if defined(__ARM_PCS_VFP)        #define ABI "armeabi-v7a/NEON (hard-float)"      #else        #define ABI "armeabi-v7a/NEON"      #endif    #else      #if defined(__ARM_PCS_VFP)        #define ABI "armeabi-v7a (hard-float)"      #else        #define ABI "armeabi-v7a"      #endif    #endif  #else   #define ABI "armeabi"  #endif#elif defined(__i386__)   #define ABI "x86"#elif defined(__x86_64__)   #define ABI "x86_64"#elif defined(__mips64)  /* mips64el-* toolchain defines __mips__ too */   #define ABI "mips64"#elif defined(__mips__)   #define ABI "mips"#elif defined(__aarch64__)   #define ABI "arm64-v8a"#else   #define ABI "unknown"#endif    return (*env)->NewStringUTF(env, "Hello from JNI !  Compiled with ABI " ABI ".");}

3.定义mk

  这里在jni 新建两个mk文件 ,Application.mk和 Android.mk内容分别如下:

Application.mk:

APP_ABI := all
 Android.mk:

# Copyright (C) 2009 The Android Open Source Project## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at##      http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.#LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE    := helloLOCAL_SRC_FILES := hello.cinclude $(BUILD_SHARED_LIBRARY)

4.在项目根目录下执行命令ndk-build

  terminal 输出如下:

appledeMacBook-Pro:JniTest apple$ ndk-build[arm64-v8a] Install        : libhello.so => libs/arm64-v8a/libhello.so[x86_64] Install        : libhello.so => libs/x86_64/libhello.so[mips64] Install        : libhello.so => libs/mips64/libhello.so[armeabi-v7a] Install        : libhello.so => libs/armeabi-v7a/libhello.so[armeabi] Install        : libhello.so => libs/armeabi/libhello.so[x86] Install        : libhello.so => libs/x86/libhello.so[mips] Install        : libhello.so => libs/mips/libhello.soappledeMacBook-Pro:JniTest apple$ 
 执行完命令会生成libs和obj文件夹

 

4.善后工作

按道理现在应该可以运行了,可是在实验过程中运行报错(可能和androidStudio的文件组织方式有关,没有深究),在网上找到解决方案:

在app/src/main 目录下新建jniLibs文件夹,并将3中生成的libs文件夹下的所有内容拷贝到此文件夹下,完成后的目录结构:



此时就可以运行了!


一直以来就像搞明白到底该怎么去写,每次实验总是出各种各样的问题,现在终于搞定了! 不一样的环境下,操作应该有差异,不过大概流程就是这样了。

0 0
原创粉丝点击