日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

android java和c混合编程_C/C++在Java项目、Android和Objective-C三大平台下实现混合编程...

發布時間:2024/10/8 c/c++ 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android java和c混合编程_C/C++在Java项目、Android和Objective-C三大平台下实现混合编程... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Android和iOS開發都支持C++開發,可以一套代碼多平臺使用。同時C++難以反編譯的特性也可以為Android開發帶來代碼的保密,另一native特性也可以提高代碼的運行效率。

一、為什么使用C/C++

便于移植,用C/C++寫得庫可以方便在其他的平臺上再次使用。

代碼的保護,由于java層代碼很容易被反編譯,而C/C++庫反匯難度較大。

提高程序的執行效率,將要求高性能的應用邏輯使用C/C++開發,從而提高應用程序的執行效率。

訪問現有開源庫,需要訪問底層的API或引用一些只有C/C++的庫。

二、開發工具介紹

盡管Android Studio可以同時編寫C++和Java代碼,寫完就可以編譯運行,但是對聯想和錯誤提示并不是非常友好,個人建議C++的整體代碼使用Visual Studio或Xcode編譯開發,聯想功能非常友好,編譯速度很快,調試也非常方便。

Visual Studio(PC)

Xcode(Mac)

Android Studio(多平臺)

eclipse(多平臺)

三、第一行代碼

1. 如何在Objective-C項目中使用C++;

在Objective-C使用C/C++非常簡單,僅僅需要把.m后綴的文件改成.mm即可使用C++,我們通常不會把.mm的文件寫到整個項目都有,而是設計一個接口,用來做兩個語言之間的橋梁,他們之間的交互僅僅在這個接口。

要點:String類型轉換

// Objective-C(NSString) -> C++(std::string)

NSString * ocString = @"Hello World,OC";

std::string cppString = [ocString UTF8String];

std::cout<

// C++(std::string) -> Objective-C(NSString)

std::string cppString2 = "Hello World,C++";

NSString *ocString2= [NSString stringWithCString:cppString2.c_str() encoding:[NSString defaultCStringEncoding]];

NSLog(@"%@",ocString2);

記得要include相關的文件

#include

#include

2.在普通的JAVA項目中使用JNI編程

由于我是在MAC下辦公,所以這里就介紹如何在MAC下進行JNI開發,在Windows平臺下的Virtual Studio也很簡單。

第一步:在Xcode下創建一個普通的C++項目

image

image

第二步:關聯JavaVM的Framework

路徑:

/System/Library/Frameworks/JavaVM.framework/Frameworks/JavaNativeFoundation.framework/

image

第三步:創建頭文件,用于和Java交互 cn_taoweiji_nativemodule_NativeDemo.h

#include

#ifndef _Included_cn_taoweiji_nativemodule_NativeDemo

#define _Included_cn_taoweiji_nativemodule_NativeDemo

#ifdef __cplusplus

extern "C" {

#endif

JNIEXPORT jint JNICALL Java_cn_taoweiji_nativemodule_NativeDemo_add

(JNIEnv *, jclass, jint, jint);

JNIEXPORT void JNICALL Java_cn_taoweiji_nativemodule_NativeDemo_say

(JNIEnv *, jclass, jstring);

JNIEXPORT jstring JNICALL Java_cn_taoweiji_nativemodule_NativeDemo_getInfo

(JNIEnv *, jclass);

JNIEXPORT void JNICALL Java_cn_taoweiji_nativemodule_NativeDemo_nativeToJava

(JNIEnv *, jclass, jobject);

#ifdef __cplusplus

}

#endif

#endif

第四步:創建實現 NativeDemo.cpp

#include "cn_taoweiji_nativemodule_NativeDemo.h"

#include

JNIEXPORT jint JNICALL Java_cn_taoweiji_nativemodule_NativeDemo_add(JNIEnv *, jclass, jint param1, jint param2)

{

jint result = param1 + param2;

return result;

}

JNIEXPORT void JNICALL Java_cn_taoweiji_nativemodule_NativeDemo_say(JNIEnv *env, jclass, jstring param)

{

// std::string -> jstring

const char *param_char = env->GetStringUTFChars(param, NULL);

std::string str = param_char;

}

JNIEXPORT jstring JNICALL Java_cn_taoweiji_nativemodule_NativeDemo_getInfo(JNIEnv *env, jclass)

{

// jstring -> std::string

std::string str = "Hi,I am C++.";

jstring result = env->NewStringUTF(str.c_str());

return result;

}

JNIEXPORT void JNICALL Java_cn_taoweiji_nativemodule_NativeDemo_nativeToJava(JNIEnv * env, jclass, jobject obj)

{

// 調用Java方法

jclass cls = env->FindClass("cn/taoweiji/nativemodule/NativeDemo");

//int subtract(int param1, int param2) -> (II)I

jmethodID mid = env->GetMethodID(cls, "subtract", "(II)I");

int result = (int) env->CallIntMethod(obj, mid, 10, 2);

// std::cout<

//常見類型轉換例子

//String getInfo();

//-> ()Ljava/lang/String;

//PackageInfo getPackageInfo(String packageName, int flags);

//-> (Ljava/lang/String;I)Landroid/content/pm/PackageInfo;;

}

第五步:編譯生成JNI文件,按 ?+B (Product -> Build).

編譯后文件

image

根據自己的電腦環境,查找編譯后的文件,我的路徑是

/Users/Wiki/Library/Developer/Xcode/DerivedData/DEMO_MAC_JNI-clxymnzifegyfaajsaattzgxqfbr/Build/Products/Debug/DEMO_MAC_JNI

第六步:編寫JNI接口

package cn.taoweiji.nativemodule;

/**

* 包名和類名稱一定要和前面的C++頭文件對應

* cn_taoweiji_nativemodule_NativeDemo.h

*/

public class NativeDemo {

public static native int add(int param1, int param2);

public static native void say(String name);

public static native String getInfo();

public static native void nativeToJava(NativeDemo nativeDemo);

public int subtract(int param1, int param2) {

System.out.println("NativeDemo:" + String.format("%s - %s = %s", param1, param2, param1 - param2));

return param1 - param2;

}

}

第七步:調用C++

public class Main {

static {

System.load("/Users/Wiki/Library/Developer/Xcode/DerivedData/DEMO_MAC_JNI-clxymnzifegyfaajsaattzgxqfbr/Build/Products/Debug/DEMO_MAC_JNI");

}

public static void main(String[] args) {

System.out.println("Hello World!");

int result = NativeDemo.add(1, 2);

System.out.println("1+2=" + String.valueOf(result));

NativeDemo.say("Hello,I am Java.");

System.out.println("getInfo:" + NativeDemo.getInfo());

NativeDemo.nativeToJava(new NativeDemo());

}

}

3. 在ANDROID項目中使用NDK

Android的JNI開發,C++文件必須編寫在獨立的module里面,Java接口代碼可以編寫在app(module),也可以和C++放在同一個module,通過gradle關聯。詳細代碼請自行下載demo瀏覽

gradle配置(NativeModule)

apply plugin: 'com.android.library'

android {

compileSdkVersion 23

buildToolsVersion "24.0.0 rc2"

defaultConfig {

minSdkVersion 14

targetSdkVersion 23

versionCode 1

versionName "1.0"

}

buildTypes {

release {

minifyEnabled false

proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

ndk {

moduleName "joyrun"

stl "stlport_static"

ldLibs "log"//用于解決__android_log_print

abiFilters "armeabi", "armeabi-v7a", "x86", "x86_64", "arm64-v8a"

//add -fexceptions to allow throw error

//add -w to "format not a string literal and no format arguments [-Werror=format-security"

cFlags "-w -fexceptions"

}

}

}

}

dependencies {

compile fileTree(dir: 'libs', include: ['*.jar'])

}

編寫JNI接口

// NativeDemo.java

package cn.taoweiji.nativemodule;

public class NativeDemo {

public static native int add(int param1, int param2);

}

編寫C++接口代碼,JNI文件目錄默認是module/src/main/jni,可以通過gradle配置改變

// cn_taoweiji_nativemodule_NativeDemo.h

#include

#ifndef _Included_cn_taoweiji_nativemodule_NativeDemo

#define _Included_cn_taoweiji_nativemodule_NativeDemo

#ifdef __cplusplus

extern "C" {

#endif

/*

* Class: cn_taoweiji_nativemodule_NativeDemo

* Method: add

* Signature: (II)I

*/

JNIEXPORT jint JNICALL Java_cn_taoweiji_nativemodule_NativeDemo_add(JNIEnv *, jclass, jint, jint);

#ifdef __cplusplus

}

#endif

#endif

// NativeDemo.cpp

#include "cn_taoweiji_nativemodule_NativeDemo.h"

JNIEXPORT jint JNICALL Java_cn_taoweiji_nativemodule_NativeDemo_add(JNIEnv *, jclass, jint param1, jint param2)

{

jint result = param1 + param2;

return result;

}

調用

// 靜態加載

static {

System.loadLibrary("joyrun");

}

//調用

int result = NativeDemo.add(1,2);

Log.i("1+2=",String.valueOf(result));

四、NDK開發要點

編譯文件分析

將NativeModule編譯后生成的aar文件后綴改成.zip解壓,可以發現里面有個jni文件,打開可以看到"armeabi", "armeabi-v7a", "x86", "x86_64", "arm64-v8a"等文件夾,再打開可以看到是以lib前綴的so格式文件,這就是編譯后的native層文件,我們平常引用的第三方庫(百度地圖)也是要添加這些文件到我們的libs文件夾,不同的名稱代表著不同平臺相關的編譯文件,市面上大多數的手機都是arm架構CPU,x86架構的手機幾乎沒人用(genymotion模擬器屬于x86平臺),所以我們通常發布APP不會考慮x86平臺,僅僅添加armeabi文件即可,但是在開發過程中建議也添加x86的so文件,以方便我們在模擬器上運行。

運行庫

Android平臺帶有一個微型的C運行庫支持庫,成為系統運行庫。該運行庫不支持一下特性:C標準庫、異常支持、RTTI支持。NDK提供了用于補充系統運行庫功能的一些額外的C++運行庫。

C++運行庫

C++異常支持

C++RTTI

C++標準庫

系統庫

No

No

No

GAbi++

No

Yes

No

STLport

No

Yes

Yes

GNU STL

Yes

Yes

Yes

STLport

STLport是一個開源的、多平臺的C標準庫實現。它提供一個C標準庫頭文件的完整集合以及對RTTI的支持。

GNU STL

GNU標準C庫,也叫libstdc-v3,是Android NDK最全面的標準C運行庫。它是一個正在開發的、以實現ISO標準C庫為目標的開源項目。

gradle配置

STL運行庫引用

"armeabi", "armeabi-v7a", "x86", "x86_64", "arm64-v8a"等平臺配置

C++輸出logcat配置

一個編譯異常解決

異常捕獲

// 生成so文件的名稱

moduleName "joyrun"

// 引入STL標準庫

stl "stlport_static"//gnustl_static

//用于解決__android_log_print

ldLibs "log"

abiFilters "armeabi", "armeabi-v7a", "x86", "x86_64", "arm64-v8a" //添加編譯的平臺

//add -fexceptions to allow throw error

//add -w to "format not a string literal and no format arguments [-Werror=format-security"

cFlags "-w -fexceptions"

LOGCAT輸出

#include

#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "tag_joyrun", __VA_ARGS__)

#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "tag_joyrun", __VA_ARGS__)

LOGE("Hello Logcat");

類型轉換

// std::string -> jstring

std::string str = "Hello World";

jstring result = env->NewStringUTF(str.c_str());

// jstring -> std::string

jstring param;

const char *param_char = env->GetStringUTFChars(param, NULL);

std::string str = param_char;

// jboolean 兩個值 JNI_TRUE、JNI_FALSE

C++調用JAVA代碼

//Java

public static native void nativeToJava(NativeDemo nativeDemo);

public int subtract(int param1, int param2) {

Log.e("NativeDemo", String.format("%s - %s = %s", param1, param2, param1 - param2));

return param1 - param2;

}

//C++

JNIEXPORT void JNICALL Java_cn_taoweiji_nativemodule_NativeDemo_nativeToJava(JNIEnv * env, jclass, jobject obj)

{

// 調用Java方法

jclass cls = env->FindClass("cn/taoweiji/nativemodule/NativeDemo");

jmethodID mid = env->GetMethodID(cls, "subtract", "(II)I");

int result = (int) env->CallIntMethod(obj, mid, 10, 2);

//常見類型轉換例子

//String getInfo();

//-> ()Ljava/lang/String;

//PackageInfo getPackageInfo(String packageName, int flags);

//-> (Ljava/lang/String;I)Landroid/content/pm/PackageInfo;;

}

一鍵生成從JAVA到C++接口代碼腳本

文件:autojavah.sh

#!/bin/sh

export ProjectPath=$(cd "../$(dirname "$1")"; pwd)

export TargetClassName="co.runner.app.jni.NativeDemo"

export SourceFile="${ProjectPath}/app/src/main/java"

export TargetPath="${ProjectPath}/jni-joyrun/src/main/jni"

cd "${SourceFile}"

javah -d ${TargetPath} -classpath "${SourceFile}" "${TargetClassName}"

echo -d ${TargetPath} -classpath "${SourceFile}" "${TargetClassName}"

五、C++面向對象及標準庫入門

C++類定義

// Demo.hpp

#ifndef Demo_hpp

#define Demo_hpp

#include

#include

class Demo{

public:

std::string name;

int age = 0;

void say();

static int add(int param1,int param2)

{

return param1 + param2;

}

};

#endif /* Demo_hpp */

類方法的實現

// Demo.cpp

#include "Demo.hpp"

#include

void Demo::say()

{

std::cout<

}

對象創建及訪問對象的成員

//對象創建

Demo d1;

Demo * d2 = new Demo;

// 運算符訪問

d1.say();

// 指針訪問

d2->say();

//靜態函數訪問

int result = Demo::add(1,2);

std::cout<

LIST鏈表

//include相關文件

#include

#include

#include

#include "Demo.hpp"

// 鏈表定義

std::list * demos = new std::list;

Demo * demo = new Demo;

demo->name = "Wiki";

demo->age = 24;

// 在后面插入數據

demos->push_back(*demo);

demo = new Demo;

demo->name = "Wiki2";

demo->age = 25;

// 在前面插入數據

demos->push_front(*demo);

// 順序鏈表遍歷

for (std::list::iterator iter = demos->begin(); iter != demos->end(); ++iter) {

iter->say();

}

// 反順序鏈表遍歷

for (std::list::reverse_iterator iter = demos->rbegin(); iter != demos->rend(); ++iter) {

iter->say();

}

// 獲取指定位置元素

std::list::iterator iter = demos->begin();

advance(iter, 1);

iter->say();

指針、引用和值

在C++中,函數可以用許多不同的方法傳遞參數,比如通過指針、引用或是直接傳值。

// 通過指針

void handle1(Demo *p);

// 通過引用

void handle1(Demo& p);

// 通過值

void handle1(Demo *demo);

堆和棧的理解

棧(stack):由操作系統自動分配釋放 ,存放函數的參數值,局部變量的值等。其操作方式類似于數據結構中的棧;

堆(heap): 一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收,分配方式倒是類似于鏈表。

Demo d1;//棧

Demo * d2 = new Demo;//堆

char c; //棧上分配

char *p = new char[3]; //堆上分配,將地址賦給了p;

垃圾回收

new和C++ delete運算符用于動態分配和撤銷內存的運算符,自己new出來的對象就要通過delete釋放內存。

delete demos;

六、開發中常用的方法及注意事項(坑)

時間戳獲取方法。

long time = time(0);

注意so文件防盜用問題。

盡量避免調用與平臺有關的方法,避免移植帶來問題。

JNI接口的包名不能帶有下劃線‘_’。

相關源代碼:

總結

以上是生活随笔為你收集整理的android java和c混合编程_C/C++在Java项目、Android和Objective-C三大平台下实现混合编程...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。