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
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,455評論 25 708
  • 文章摘要1、 c、c++項目的創建2、添加C、C++項目依賴庫4、配置Gradle,編譯lib so庫 英文文獻 ...
    Android那些事兒閱讀 12,878評論 0 54
  • 一、NDK產生的背景 Android平臺從誕生起,就已經支持C、C++開發。眾所周知,Android的SDK基于J...
    Ten_Minutes閱讀 3,554評論 1 27
  • 1、產品定位 信息聚合性工具 官方描述:基于興趣的極簡信息推送工具“只看你想看的 ” 2、用戶描述 對于信息篩選有...
    沉默的羔洋閱讀 553評論 0 1
  • 我又要開始講故事了。 故事源于生活,就像有些電視劇的情節,你覺得狗血、太湊巧,可生活中真的每時每刻都在發生著。 小...
    一縷仙兒氣閱讀 362評論 0 1