配色: 字号:
C++在JavaAndroid和Objective-C三大平台下实现混合编程
2016-11-04 | 阅:  转:  |  分享 
  
C/C++在Java、Android和Objective-C三大平台下实现混合编程

本文主要介绍C/C++在Java、Android和Objective-C三大平台下实现混合编程,这里举例说明实现不同平台用C/C++实现编程的方法,有兴趣的小伙伴可以参考下

Android和iOS开发都支持C++开发,可以一套代码多平台使用。同时C++难以反编译的特性也可以为Android开发带来代码的保密,另一native特性也可以提高代码的运行效率。

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

便于移植,用C/C++写得库可以方便在其他的平台上再次使用。

代码的保护,由于java层代码很容易被反编译,而C/C++库反汇难度较大。

提高程序的执行效率,将要求高性能的应用逻辑使用C/C++开发,从而提高应用程序的执行效率。

访问现有开源库,需要访问底层的API或引用一些只有C/C++的库。

二、开发工具介绍

尽管AndroidStudio可以同时编写C++和Java代码,写完就可以编译运行,但是对联想和错误提示并不是非常友好,个人建议C++的整体代码使用VisualStudio或Xcode编译开发,联想功能非常友好,编译速度很快,调试也非常方便。

VisualStudio(PC)

Xcode(Mac)

AndroidStudio(多平台)

eclipse(多平台)

三、第一行代码

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

在Objective-C使用C/C++非常简单,仅仅需要把.m后缀的文件改成.mm即可使用C++,我们通常不会把.mm的文件写到整个项目都有,而是设计一个接口,用来做两个语言之间的桥梁,他们之间的交互仅仅在这个接口。

要点:String类型转换

1

2

3

4

5

6

7

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

NSStringocString=@"HelloWorld,OC";

std::stringcppString=[ocStringUTF8String];

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

std::stringcppString2="HelloWorld,C++";

NSStringocString2=[NSStringstringWithCString:cppString2.c_str()encoding:[NSStringdefaultCStringEncoding]];

NSLog(@"%@",ocString2); 记得要include相关的文件

#include#include

2.在普通的JAVA项目中使用JNI编程

由于我是在MAC下办公,所以这里就介绍如何在MAC下进行JNI开发,在Windows平台下的VirtualStudio也很简单。

第一步:在Xcode下创建一个普通的C++项目









第二步:关联JavaVM的Framework

路径:

/System/Library/Frameworks/JavaVM.framework/Frameworks/JavaNativeFoundation.www.visa158.com.framework/



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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20 #include

#ifndef_Included_cn_taoweiji_nativemodule_NativeDemo

#define_Included_cn_taoweiji_nativemodule_NativeDemo

#ifdef__cplusplus

extern"C"{

#endif

JNIEXPORTjintJNICALLJava_cn_taoweiji_nativemodule_NativeDemo_add

(JNIEnv,jclass,jint,jint);

JNIEXPORTvoidJNICALLJava_cn_taoweiji_nativemodule_NativeDemo_say

(JNIEnv,jclass,jstring);

JNIEXPORTjstringJNICALLJava_cn_taoweiji_nativemodule_NativeDemo_getInfo

(JNIEnv,jclass);

JNIEXPORTvoidJNICALLJava_cn_taoweiji_nativemodule_NativeDemo_nativeToJava

(JNIEnv,jclass,jobject);

#ifdef__cplusplus

}

#endif

#endif 第四步:创建实现NativeDemo.cpp

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36 #include"cn_taoweiji_nativemodule_NativeDemo.h"

#include

JNIEXPORTjintJNICALLJava_cn_taoweiji_nativemodule_NativeDemo_add(JNIEnv,jclass,jintparam1,jintparam2)

{

jintresult=param1+param2;

returnresult;

}

JNIEXPORTvoidJNICALLJava_cn_taoweiji_nativemodule_NativeDemo_say(JNIEnvenv,jclass,jstringparam)

{

//std::string->jstring

constcharparam_char=env->GetStringUTFChars(param,NULL);

std::stringstr=param_char;

}

JNIEXPORTjstringJNICALLJava_cn_taoweiji_nativemodule_NativeDemo_getInfo(JNIEnvenv,jclass)

{

//jstring->std::string

std::stringstr="Hi,IamC++.";

jstringresult=env->NewStringUTF(str.c_str());

returnresult;

}

JNIEXPORTvoidJNICALLJava_cn_taoweiji_nativemodule_NativeDemo_nativeToJava(JNIEnvenv,jclass,jobjectobj)

{

//调用Java方法

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

//intsubtract(intparam1,intparam2)->(II)I

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

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

//std::cout<
//常见类型转换例子

//StringgetInfo();

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

//PackageInfogetPackageInfo(StringpackageName,intflags);

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

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

编译后文件



根据自己的电脑环境,查找编译后的文件,我的路径是

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

第六步:编写JNI接口

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15 packagecn.taoweiji.nativemodule;

/

包名和类名称一定要和前面的C++头文件对应

cn_taoweiji_nativemodule_NativeDemo.h

/

publicclassNativeDemo{

publicstaticnativeintadd(intparam1,intparam2);

publicstaticnativevoidsay(Stringname);

publicstaticnativeStringgetInfo();

publicstaticnativevoidnativeToJava(NativeDemonativeDemo);

publicintsubtract(intparam1,intparam2){

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

returnparam1-param2;

}

} 第七步:调用C++

1

2

3

4

5

6

7

8

9

10

11

12

13 publicclassMain{

static{

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

}

publicstaticvoidmain(String[]args){

System.out.println("HelloWorld!");

intresult=NativeDemo.add(1,2);

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

NativeDemo.say("Hello,IamJava.");

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

NativeDemo.nativeToJava(newNativeDemo());

}

} 3.在ANDROID项目中使用NDK

Android的JNI开发,C++文件必须编写在独立的module里面,Java接口代码可以编写在app(module),也可以和C++放在同一个module,通过gradle关联。详细代码请自行下载demo浏览

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30 gradle配置(NativeModule)

applyplugin:''com.android.library''

android{

compileSdkVersion23

buildToolsVersion"24.0.0rc2"

defaultConfig{

minSdkVersion14

targetSdkVersion23

versionCode1

versionName"1.0"

}

buildTypes{

release{

minifyEnabledfalse

proguardFilesgetDefaultProguardFile(''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-fexceptionstoallowthrowerror

//add-wto"formatnotastringliteralandnoformatarguments[-Werror=format-security"

cFlags"-w-fexceptions"

}

}

}

}

dependencies{

compilefileTree(dir:''libs'',include:[''.jar''])

} 编写JNI接口

1

2

3

4

5 //NativeDemo.java

packagecn.taoweiji.www.hunanwang.netivemodule;

publicclassNativeDemo{

publicstaticnativeintadd(intparam1,intparam2);

} 编写C++接口代码,JNI文件目录默认是module/src/main/jni,可以通过gradle配置改变

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17 //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

/

JNIEXPORTjintJNICALLJava_cn_taoweiji_nativemodule_NativeDemo_add(JNIEnv,jclass,jint,jint);

#ifdef__cplusplus

}

#endif

#endif 1

2

3

4

5

6

7 //NativeDemo.cpp

#include"cn_taoweiji_nativemodule_NativeDemo.h"

JNIEXPORTjintJNICALLJava_cn_taoweiji_nativemodule_NativeDemo_add(JNIEnv,jclass,jintparam1,jintparam2)

{

jintresult=param1+param2;

returnresult;

} 调用

1

2

3

4

5

6

7 //静态加载

static{

System.loadLibrary("joyrun");

}

//调用

intresult=NativeDemo.add(1,2);

Log.i("1+2=",String.valueOf(result)); C++运行库 C++异常支持 C++RTTI C++标准库 系统库 No No No GAbi++ No Yes No STLport No Yes Yes GNUSTL Yes Yes Yes 1

2

3

4

5

6

7

8

9

10 //生成so文件的名称

moduleName"joyrun"

//引入STL标准库

stl"stlport_static"//gnustl_static

//用于解决__android_log_print

ldLibs"log"

abiFilters"armeabi","armeabi-v7a","x86","x86_64","arm64-v8a"//添加编译的平台

//add-fexceptionstoallowthrowerror

//add-wto"formatnotastringliteralandnoformatarguments[-Werror=format-security"

cFlags"-w-fexceptions" LOGCAT输出

1

2

3

4

5 #include

#defineLOGI(...)__android_log_print(ANDROID_LOG_INFO,"tag_joyrun",__VA_ARGS__)

#defineLOGE(...)__android_log_print(ANDROID_LOG_ERROR,"tag_joyrun",__VA_ARGS__)

LOGE("HelloLogcat"); 类型转换

1

2

3

4

5

6

7

8 //std::string->jstring

std::stringstr="HelloWorld";

jstringresult=env->NewStringUTF(str.c_str());

//jstring->std::string

jstringparam;

constcharparam_char=env->GetStringUTFChars(param,NULL);

std::stringstr=param_char;

//jboolean两个值JNI_TRUE、JNI_FALSE C++调用JAVA代码

//Java

1

2

3

4

5 publicstaticnativevoidnativeToJava(NativeDemonativeDemo);

publicintsubtract(intparam1,intparam2){

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

returnparam1-param2;

} //C++

1

2

3

4

5

6

7

8

9

10

11

12

13 JNIEXPORTvoidJNICALLJava_cn_taoweiji_nativemodule_NativeDemo_nativeToJava(JNIEnvenv,jclass,jobjectobj)

{

//调用Java方法

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

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

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

//常见类型转换例子

//StringgetInfo();

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

//PackageInfogetPackageInfo(StringpackageName,intflags);

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

} 一键生成从JAVA到C++接口代码脚本

文件:autojavah.sh

1

2

3

4

5

6

7

8 #!/bin/sh

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

exportTargetClassName="co.runner.app.jni.NativeDemo"

exportSourceFile="${ProjectPath}/app/src/main/java"

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

cd"${SourceFile}"

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

echo-d${TargetPath}-classpath"${SourceFile}""${TargetClassName}" 五、C++面向对象及标准库入门

C++类定义

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16 //Demo.hpp

#ifndefDemo_hpp

#defineDemo_hpp

#include

#include

classDemo{

public:

std::stringname;

intage=0;

voidsay();

staticintadd(intparam1,intparam2)

{

returnparam1+param2;

}

};

#endif/Demo_hpp/ 类方法的实现

1

2

3

4

5

6

7 //Demo.cpp

#include"Demo.hpp"

#include

voidDemo::say()

{

std::cout<<"name="<
} 对象创建及访问对象的成员

1

2

3

4

5

6

7

8

9

10 //对象创建

Demod1;

Demod2=newDemo;

//运算符访问

d1.say();

//指针访问

d2->say();

//静态函数访问

intresult=Demo::add(1,2);

std::cout<<"1+2="<
2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29 //include相关文件

#include

#include

#include

#include"Demo.hpp"

//链表定义

std::listdemos=newstd::list;

Demodemo=newDemo;

demo->name="Wiki";

demo->age=24;

//在后面插入数据

demos->push_back(demo);

demo=newDemo;

demo->name="Wiki2";

demo->age=25;

//在前面插入数据

demos->push_front(demo);

//顺序链表遍历

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

iter->say();

}

//反顺序链表遍历

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

iter->say();

}

//获取指定位置元素

std::list::iteratoriter=demos->begin();

advance(iter,1);

iter->say(); 1

2

3

4

5

6 //通过指针

voidhandle1(Demop);

//通过引用

voidhandle1(Demo&p);

//通过值

voidhandle1(Demodemo); 1

2

3

4 Demod1;//栈

Demod2=newDemo;//堆

charc;//栈上分配

charp=newchar[3];//堆上分配,将地址赋给了p;





















献花(0)
+1
(本文系白狐一梦首藏)