C/C++在Android开发中的应用

JNI开发系列阅读

1. 前言

1.1 Android SDK介绍

Android是基于Linux内核的一个手机操作系统,谷歌提供了开发包(Android SDK),程序员可以通过开发包开发Android App(应用程序)。Android SDK提供Java语言接口,因此Android应用是使用Java开发的。

1.2 使用纯Java开发App的缺点

在某些场合下,使用纯Java开发Android应用程序不完美,比如:

  • 有高性能算法,Java语言无法满足
  • 有跨平台需求,希望将App移植到iOS
  • 已有代码的重用

1.3 引入NDK

早在Android 1.6(2009年)时,google就提供了NDK(native development kit),NDK包括了一套Android的交叉编译环境和开发库,利用它可以编写C/C++程序,并编译成Android环境下使用的动态库,Java代码通过Jni规范,调用C/C++写的动态库。

目前最新的Android Studio 2.2中,集成了C/C++开发环境,开发人员在使用C/C++更加简单了。

2. 课程内容

NDK中文官方开发技术文档地址

ndk

下载配置NDK

NDK下载地址

ndk

配置NDK

ndk
ndk

如果不配置NDK路径,会报NDK没有配置错误

ndk

JNI开发HelloWorld

把 Include C++ support的勾打上

Include C++ support

选择C++11和Toolchain Default均可,C++11有更多的新特性和功能

jni

点击Finish后,进入工程目录,如图所示,除了java文件夹外多了一个cpp文件夹,cpp就是存放c和c++代码的文件夹

jni

配置NDK开发环境中遇到的坑

Failed to find CMake

jni

什么,CMake是什么鬼,原来,在Android Studio 2.2 后,NDK开发更加人性化了,使用了CMake,一款外部构建工具,可与 Gradle 搭配使用来构建原生库。如果您只计划使用 ndk-build,则不需要此组件。还有LLDB,一种调试程序,Android Studio 使用它来调试原生代码

点击Install CMake and sync project,提示如下错误

jni
Gradle sync failed: Failed to find CMake.
Install from Android Studio under File/Settings/Appearance & Behavior/System Settings/Android SDK/SDK Tools/CMake.
Expected CMake executable at D:\android-sdk\cmake\bin\cmake.exe.
Consult IDE log for more details (Help | Show Log)

原来是我使用了代理,因为之前Google的链接需要翻墙才能够使用,所以配置了某代理,但是该代理不管用,在设置中把代理去掉即可。在Google在中国开了发布会后,Google的链接可以使用了,Android开发官网也可以上了,而且翻译了大量的技术文档,方便了英语不太好的同学

jni

打开 SDK Manager,安装上CMake和LLDB

jni开发
jni开发
jni开发

更多更详细的NDK开发文档,请看Android官方中文文档向您的项目添加 C 和 C++ 代码

2.3 Android Java代码调用C++代码

Java部分代码

public class Jni {
    static  {
        System.loadLibrary("bc-lib"); // libbc-lib.so
    }
 
    private static Jni obj = new Jni();
    private Jni(){}
 
    public static Jni instance(){
        return obj;
    }
 
    // native接口
    public native boolean Login(String username, String password, String type);
    public native boolean Reg(String username, String password, String mobile, String email, String id);
    public native boolean LocationChange(double lng, double lat);
    public native boolean StartOrder(double lng1, double lat1, double lng2, double lat2);
}

C++部分代码

JNIEXPORT jboolean JNICALL Java_cn_xueguoliang_hc_Jni_Login
        (JNIEnv *env, jobject /* Jni object */, jstring jUsername, jstring jPassword, jstring type)
{
    return (jboolean)User::instance()->Login(j2c(env, jUsername), j2c(env, jPassword),
    j2c(env, type));
}
 
JNIEXPORT jboolean JNICALL Java_cn_xueguoliang_hc_Jni_Reg
        (JNIEnv *env, jobject /* Jni object */,
         jstring jUsername, jstring jPassword, jstring mobile, jstring email, jstring id)
{
    return (jboolean)User::instance()->Reg(
            j2c(env, jUsername),
            j2c(env, jPassword),
            j2c(env, mobile),
            j2c(env, email),
            j2c(env, id));
}
 
JNIEXPORT jboolean JNICALL Java_cn_xueguoliang_hc_Jni_LocationChange
        (JNIEnv *, jobject, jdouble lng, jdouble lat)
{
    User::instance()->LocationChange(lng, lat);
    return (jboolean)true;
}
 
 
JNIEXPORT jboolean JNICALL Java_cn_xueguoliang_hc_Jni_StartOrder
        (JNIEnv *, jobject, jdouble lng1, jdouble lat1, jdouble lng2, jdouble lat2)
{
    return (jboolean)Order::instance()->start(lng1, lat1, lng2, lat2);
}

2.4 C++代码调用Java代码

Java代码

public class Jni {
    static {
        System.loadLibrary("native-lib");
    }
 
    private static Jni obj = new Jni();
    public static Jni instance()
    {
        return obj;
    }
 
    public native void HelloWorld();
 
    void callByCpp()
    {
        Log.e("JniCallback", "hello java");
    }
}

C++代码

extern "C"
void
Java_com_example_xueguoliang_test_Jni_HelloWorld(
        JNIEnv* env,
        jobject  This ) {
    std::string hello = "Hello from C++";
 
    jclass jniClass = env->FindClass("com/example/xueguoliang/test/Jni");
    jmethodID jmethodID1 = env->GetMethodID(jniClass, "callByCpp", "()V");
    env->CallVoidMethod(This, jmethodID1);
 
    return;
}

2.5 Java和C++字符串转换

jstring c2j(JNIEnv* env, string cstr)
{
    return env->NewStringUTF(cstr.c_str());
}
 
string j2c(JNIEnv* env, jstring jstr)
{
    string ret;
    jclass stringClass = env->FindClass("java/lang/String");
    jmethodID getBytes = env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B");
 
    // 把参数用到的字符串转化成java的字符
    jstring arg = c2j(env, "utf-8");
 
    jbyteArray jbytes = (jbyteArray)env->CallObjectMethod(jstr, getBytes, arg);
 
    // 从jbytes中,提取UTF8格式的内容
    jsize byteLen = env->GetArrayLength(jbytes);
    jbyte* JBuffer = env->GetByteArrayElements(jbytes, JNI_FALSE);
 
    // 将内容拷贝到C++内存中
    if(byteLen > 0)
    {
        char* buf = (char*)JBuffer;
        std::copy(buf, buf+byteLen, back_inserter(ret));
    }
 
    // 释放
    env->ReleaseByteArrayElements(jbytes, JBuffer, 0);
    return ret;
}

2.6 javah和javap

javah用于生成native接口定义,比如

javah -d ../cpp/ com.example.xueguoliang.test.Jni

javap用于生成java函数的签名,比如

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,368评论 25 707
  • 文章摘要1、 c、c++项目的创建2、添加C、C++项目依赖库4、配置Gradle,编译lib so库 英文文献 ...
    Android那些事儿阅读 12,542评论 0 54
  • 一、NDK产生的背景 Android平台从诞生起,就已经支持C、C++开发。众所周知,Android的SDK基于J...
    Ten_Minutes阅读 3,472评论 1 27
  • 1、产品定位 信息聚合性工具 官方描述:基于兴趣的极简信息推送工具“只看你想看的 ” 2、用户描述 对于信息筛选有...
    沉默的羔洋阅读 526评论 0 1
  • 我又要开始讲故事了。 故事源于生活,就像有些电视剧的情节,你觉得狗血、太凑巧,可生活中真的每时每刻都在发生着。 小...
    一缕仙儿气阅读 347评论 0 1