美文网首页android
02_JNI-Eclipse上的开发环境

02_JNI-Eclipse上的开发环境

作者: 对方不想理你并向你抛出一个异常 | 来源:发表于2017-02-26 18:42 被阅读180次

    开发步骤

    • 确认eclipse安装了CDT , eclipse中查看:Hlep--->Install New Software ---> 点击右下角already installed --->Plug-ins ---> 查看CDT是否安装* 新建Android项目* 在MainActivity.java文件中声明本地方法
    public native String  helloFromC();
    
    
    • 在项目根目录下新建jni的Folder
    • 在jni目录下新建hello.c
    • 在hello.c文件写与java文件中对应的native方法的函数,c中本地函数命名规则:Java_包名(.需要换成_)类名本地方法名函数中有两个参数:
      1,jobject obj:调用本地函数的Java对象,在本例中就是MainActivity实例
      2,JNIEnv* env:是结构体JNINativeInterface 的二级指针,JNIEnv是结构体 JNINativeInterface 的一级指针,JNINativeInterface结构体中定义了大量的函数指针,这些函数指针在JNI开发中会经常使用
      3,(*env)->:调用结构体中的函数指针
    #include <stdio.h>
    #include <stdlib.h>
    #include <jni.h>
    
    jstring Java_com_huachao_jnihelloworld_MainActivity_helloFromC(JNIEnv* env , jobject thiz){
    
        char* cstr = "hello from c";
    
        return (*env)->NewStringUTF(env,cstr);
    } 
    
    • 配置ndk环境变量(path中添加ndk路径)
    • 在命令行cd到项目目录下:F:\as\Eclipse\personal\JNI\01-JNIHelloWorld>
    • 执行ndk-build命令,提示
    Android NDK: WARNING: APP_PLATFORM android-21 is larger than android:minSdkVers
    on 8 in ./AndroidManifest.xml
    Android NDK: Your APP_BUILD_SCRIPT points to an unknown file: ./jni/Android.mk
    
    
    • 在jni目录下,新建Android.mk文件
    LOCAL_PATH := $(call my-dir)//设置为当前目录
    include $(CLEAR_VARS)                //清空变量
    
    LOCAL_MODULE    := hello//编译生成的文件名称
    LOCAL_SRC_FILES := hello.c//.c源文件名称
    
    include $(BUILD_SHARED_LIBRARY)
    
    

    注意:
    1,LOCAL_MODULE := hello,编译后,编译器会给文件添加lib前缀和.so后缀,例如本例生成libhello.so
    2,若新建的文件夹名不是jni,或者修改了jni的文件夹名称,则在ndk-build的时候,不能在项目目录下build,要cd到这个目录下,再执行ndk-build

    • 再次在命令行中在项目目录下执行ndk-build命令,提示Install,生成.so文件,表示成功
    • 在MainActivity.java中调用
    public class MainActivity extends Activity {
        static{
            System.loadLibrary("hello");
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
        public native String  helloFromC();
        public void onClick(View v) {
            String c = helloFromC();
            Toast.makeText(this, c, Toast.LENGTH_LONG).show();
        }
    }  
    

    开发中常见错误

    方法名

    • native方法名不能包含_,因为c语言的函数命名规范也是使用的_,会产生冲突,最后会报Native method not found错误
    • 如果本地方法一定要有_,那么c函数_后加1区分,例如:
    public native String  hello_FromC(); 
    jstring Java_com_huachao_jnihelloworld_MainActivity_hello_1FromC(JNIEnv* env , jobject thiz){
    } 
    
    • 如果native名字太复杂,下划线太多,可以使用javah命令自动生成c的函数名
      1,如果是jdk1.6,cd到:项目根目录\bin\classes>
      2,如果是1.7及以上,cd到:项目根目录\src>
      3,执行命令:javah -jni 包名.类名
      在本例中如下:

    F:\as\Eclipse\personal\JNI\01-JNIHelloWorld\src>javah -jni com.huachao.jnihelloworld.MainActivity

    • 如果没有System.loadLibrary("hello");,也会报Native method not found错误
    • 注意:System.loadLibrary("hello");加载的库名称是Android.mk中LOCAL_MODULE := hello的名称,而不是生成的.so文件的名称

    Application.mk配置

    多平台

    • 如果Application.mk没有文件,或者在Application.mk文件中不指定APP_ABI,在NDK默认只编译armeabi的平台的库
    • 在jni目录下新建Application.mk文件
      1, APP_ABI := all //所有平台
      2, APP_ABI := armeabi-v7a
      3, APP_ABI := x86
      4, APP_ABI := mips
      5, APP_ABI := armeabi armeabi-v7a x86 mips //也是所有平台

    SDK版本配置

    • 在Application.mk添加 APP_PLATFORM := android-11
    • 版本对应
    android-3 -> Official Android 1.5 system imagesandroid-4 -> Official Android 1.6 system imagesandroid-5 -> Official Android 2.0 system imagesandroid-6 -> Official Android 2.0.1 system imagesandroid-7 -> Official Android 2.1 system imagesandroid-8 -> Official Android 2.2 system imagesandroid-9 -> Official Android 2.3 system imagesandroid-14 -> Official Android 4.0 system imagesandroid-18 -> Official Android 4.3 system images
    
    

    简单开发流程

    • 新建Android项目
    • 如上所述,在MainActivity中添加native方法
    • 指定项目的NDK目录:Eclipse视图中Window --> Preferences -->Android --> NDK --> 选择NDK目录(本例中目录F:\as\plugin\android-ndk-r9d) --> 点击 apply,然后点击OK
    • 在Eclipse视图中,在项目目录上右键点击-->Android Tools -->Add Native Support --> 输入自定义名称(本例中hello) --> 点击Finish
      注意:
      1,如果Finish点不了,那么可能是上一个步骤没做
      2,如果Android Tools中没有Add Native Support这个菜单:将资料中的
      com.android.ide.eclipse.ndk_23.0.2.1259578.jar文件拷贝到eclipse的安装目录的plugin目录下,然后重启Eclipse
    • 将hello.cpp重命名为hello.c,并在Android.mk文件中做相应修改
    • 用javah命令生成头文件
    • 在项目目录上右键点击 --> Properties -->C/C++ General --> Paths and Symbols --> 选中Includes选项卡 --> Add --> 添加NDK的include目录(本例F:\as\plugin\android-ndk-r9d\platforms\android-14\arch-arm\usr\include)--> 点击Apply(会提示是否rebuild,点击YES) --> 点击OK
      1, platforms的版本最好选择Application.mk设置的最低版本
      2,
      Paste_Image.png
    • 编译
      1,切换到C/C++视图
      2,点击那个类似锤子的按钮,进行编译,


      Paste_Image.png
    • 在Java中调用和上面一样
    • 提示:运行项目最好切换到Java视图,不然可能会报错

    注意:在eclipse的jni开发中,包名不能包含下划线,否则在运行时运行不了,但是却不报错

    在JNI开发中,指定NDK目录,是更换workspace的时候才要做,其他的都是每次新建项目都是要做的

    • 设置编译时不编译C/C++代码,也不生成.so库(当so库已经生成完毕时,只是修改了java代码可以这样设置)
      Paste_Image.png

    取消上面两个红色箭头的勾选

    绕过JNI调用C代码

    • 广泛使用的地方:
      1,自定制平板,机顶盒
      2,Android手机病毒
      3,黑客操作

    • 纯c语言开发程序 ,步骤如下:

    • 1.下载编译器和链接器软件.Sourcery G++ Lite Edition for ARM.

    arm-none-linux-gnueabi-gcc.exe是编译命令
    bin/arm-none-linux-gnueabi-ld.exe是链接命令

    • 2.编写c源文件
     #include <stdio.h>
     int main()
     {
     printf("Hello, Android!\n");
     return 0;
     }
    
    • 3.编译hello.c源文件
      进入cmd
      执行 arm-none-linux-gnueabi-gcc HelloWorld.c -static -o hellostatic

    • 4.将hellostatic文件传输手机
      adb push hellostatic /data/data/

    • 5.改变文件的授权
      adb shell chmod 777 /data/data/hellostatic

    • 6.运行程序
      adb shell
      cd /data/data
      ./hellostatic

    • 上面的实质就是把.c文件编译成静态库,然后在命令行执行,其实系统里面已经有很多这种可执行的文件

      Paste_Image.png
    • 在java中执行可执行文件
    public void binExce(View v) {//点击事件
         try {
    //     Process process = Runtime.getRuntime().exec("/data/data/hello");//hello是我们自己编译并且放入的库文件
     Process process = Runtime.getRuntime().exec("ps");
     InputStream is = process.getInputStream();
     DataInputStream dis = new DataInputStream(is);
     String res ;
     StringBuilder sb = new StringBuilder();
     while ((res = dis.readLine()) !=null) {
     sb.append(res);
     sb.append("\n");
     }
     System.out.println("--->"+sb.toString());
     } catch (IOException e) {
     e.printStackTrace();
     }
     }
    
    

    注意:上述步骤只在Android 4.x下测试生效,高版本没有测试

    相关文章

      网友评论

        本文标题:02_JNI-Eclipse上的开发环境

        本文链接:https://www.haomeiwen.com/subject/rlxawttx.html