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;
|
|