02_JNI-Eclipse上的开发环境

开发步骤

  • 确认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下测试生效,高版本没有测试

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • Android游戏开发实践(1)之NDK与JNI开发02 承接上篇Android游戏开发实践(1)之NDK与JNI...
    AlphaGL阅读 3,744评论 0 24
  • 一、NDK产生的背景 Android平台从诞生起,就已经支持C、C++开发。众所周知,Android的SDK基于J...
    Ten_Minutes阅读 3,487评论 1 27
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,830评论 25 707
  • 本人非技术人员,也非专业测试人员。只是从自己日常使用的角度来对比这几个笔记类app。(还有就是,既然这是自己选的题...
    大梦斋阅读 4,395评论 0 3
  • 我把门打开 门打开了风 风打开我身体 把污浊灌进去 冷酷的风 缠绕在我喉结中 上下翻腾 切割出苍白肌肤 同归的人 ...
    以名北墨阅读 257评论 0 3