|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
由于封闭文档写的相当好在遇到新框架的时候弄明白框架的功能去文档里搜搜框架的ProgrammingGuide很有用要弄明白框架类的继承结构写iOS的程序不一定都是用OBJC引子
头几天,我分享了一下qtforandroid,从人人的反响和回馈,我看到两种极度的形态。一个是:“太好了!想做Android开辟可是不想转java,这下不必了!”另外一个是:“不要在Qt上华侈工夫了,它顶多在Android上跑个Helloworld,其余甚么也跑不了。”
我先说说我对QtforAndroid的客不雅熟悉。起首,从现有阶段看,不能不供认TA并非一个成熟的手艺(工具)。在年夜型项目中,仍是不倡议利用qtforandroid开辟的,由于材料太少,我们没法疾速深切的在年夜脑创建起qtforandroid收集,在碰到成绩的时分,办理起来就很辣手。可是,毫不是说仅仅就可以跑个Helloworld,假如真的这么一无可取,TA就没有存在的意义,也就不会吸引多量开辟者深切研讨和优化了。要晓得,世上最复杂的事变就是品评和痛斥。我再次夸大一下,我只是分享我所看到的晓得的,不带任何导游性。关于手艺自己,仁者见仁,智者见智。
咀嚼与探求
当我看到这么一个手艺工具,我的猎奇心使令我探求一下(1)TA究竟是怎样完成的,(2)程序在Android上实行效力和功能怎样,(3)较惯例的Androidjava开辟和jnic++开辟而言,二者之间有甚么能够互相自创,(4)倘使Google真的开放纯c++开辟,那末java和qtforandroid又是如何的一番风景?
一个开辟者分享他某一个程序的计划思绪:在Qt下经由过程jni失掉javaEnv,从而利用GPS等androidAPI,而且已完成:
- JNIEnv*currEnv;
- currEnv=0;
- if(currVM->AttachCurrentThread((void**)&currEnv,NULL)<0)
- {
- emiterror("CannotattachthecurrentthreadtotheVM");
- }
JNIEnv*currEnv;currEnv=0;if(currVM->AttachCurrentThread((void**)&currEnv,NULL)<0){emiterror("CannotattachthecurrentthreadtotheVM");}
大概由于我对Qt旌旗灯号和槽的情有独钟,看到emit就感应很亲热,而且被深深的吸引了。那末从Qtforandroid的qt工程源码看,究竟是怎样在android上乐成启动并运转的呢?
启动流程剖析
用qt-creator创立的每一个使用程序中,src下的文件都是基础不异。由于启动程序,创立接口,链接库,这些操纵是每一个使用程序所必须的,最后的qt程序被编译成了lib**.so的静态库,当挪用JNI接口startQtApp函数时真正启动了qt程序。
实行程序的出口在src/eu/licentia/necessitas/industrius/QtActivity.java中,onCreate挪用startapp反省需要的库文件,扩大包,插件是不是存在,并加载.链接ministro服务,得知ministro服务如今的形态,假如短少qt库则必要借助ministro服务下载。
privatevoidstartApp(finalbooleanfirstStart)
{
try
{
ActivityInfoai=getPackageManager().getActivityInfo(getComponentName(),PackageManager.GET_META_DATA);
if(!ai.metaData.containsKey("android.app.qt_libs_resource_id"))
{
//Norequiredqtlibs?
//Probablythisapplicationwascompiledusingstaticqtlibs
//orallqtlibsareprebundledintothepackage
m_ministroCallback.libs(null,null,null,0,null);
return;
}
intresourceId=ai.metaData.getInt("android.app.qt_libs_resource_id");
m_qtLibs=getResources().getStringArray(resourceId);
m_ministroCallback.libs(libs,"QT_IMPORT_PATH=/data/local/qt/imports QT_PLUGIN_PATH=/data/local/qt/plugins",
"-platform android",0,null);
return;
}
try{
if(!bindService(newIntent(eu.licentia.necessitas.ministro.IMinistro.class.getCanonicalName()),
m_ministroConnection,Context.BIND_AUTO_CREATE))
thrownewSecurityException("");
}catch(SecurityExceptione){}
}
使用程序必要的库由AndroidManifest.xml中的qt_libs_resource_id项指定,这一项来自于res/values/libs.xml中的qt_libs项。
- <?xmlversionxmlversion=1.0encoding=utf-8?>
- <resources>
- <arrayname="qt_libs">
- <item>QtCore</item>
- <item>QtGui</item>
- </array>
- <arraynamearrayname="bundled_libs"/>
- </resources>
<?xmlversion=1.0encoding=utf-8?><resources><arrayname="qt_libs"><item>QtCore</item><item>QtGui</item></array><arrayname="bundled_libs"/></resources>
qt使用程序的启动也是借助ministro服务,必要ministro供应响应的库撑持,当失掉响应的库后创立线程,启动startApplication。
privateIMinistroCallbackm_ministroCallback=newIMinistroCallback.Stub(){
@Override
publicvoidlibs(finalString[]libs,finalStringevnVars,finalStringparams,
interrorCode,StringerrorMessage)throwsRemoteException{
runOnUiThread(newRunnable(){
@Override
publicvoidrun(){
startApplication(libs,evnVars,params);
}
});
}
};
在src/eu/licentia/necessitas/industriusQtApplication.java中startApplication函数,先启动android的Plugin然后挪用一个JNI接口startQtApp启动qt程序。
QtActivity.java中的startApplication函数会挪用QtApplication.java中的startApplication。
publicstaticvoidstartApplication(Stringparams,Stringenvironment)
{
if(params==null)
params="-platform android";
synchronized(m_mainActivityMutex)
{
startQtAndroidPlugin();
setDisplayMetrics(m_displayMetriCSScreenWidthPixels,
m_displayMetricsScreenHeightPixels,
m_displayMetricsDesktopWidthPixels,
m_displayMetricsDesktopHeightPixels,
m_displayMetricsXDpi,
m_displayMetricsYDpi);
if(params.length()>0)
params=" "+params;
startQtApp("QtApp"+params,environment);
m_started=true;
}
}
startQtApp时会启动线程startMainMethod,在startMainMethod线程中会将lib**.so中main函数出口以库函数接口的情势再次实行,恢复了qt可实行程序的原本脸孔,在背景实行
这部分源码在android-lighthouse的源码中。
JNI的部分代码
extern"C"intmain(int,char**);//usethestandardmainmethodtostarttheapplication
staticvoid*startMainMethod(void*/*data*/)
{
char**params;
params=(char**)malloc(sizeof(char*)*m_applicationParams.length());
for(inti=0;i<m_applicationParams.size();i++)
params=(char*)m_applicationParams.constData();
intret=main(m_applicationParams.length(),params);
......
}
重写onKeydown
经由过程上述挪用历程能够晓得,android程序是如何经由过程JNI来挪用qt库中的函数。其他相干android的的JNI接口在,plugins/platforms/android/下,好比keydown。
在src/eu/licentia/necessitas/industriusQtActivity.java重写了onKeydown函数,挪用JNI函数keyDown完成。
keyDown的完成在plugins/platforms/android/mw/androidjnimain.cpp中
staticvoidkeyDown(JNIEnv*/*env*/,jobject/*thiz*/,jintkey,jintunicode,jintmodifier)
{
……
intmappedKey=mapAndroidKey(key);
if(mappedKey==Qt::Key_Close)
{
qDebug()<<"handleCloseEvent"<<mLastTLW;
QWindowSystemInterface::handleCloseEvent(mLastTLW);
}
else
QWindowSystemInterface::handleKeyEvent(0,QEvent::KeyPress,mappedKey,modifiers,QChar(unicode),true);
//经由过程JNI的匡助,转化成了Qt的完成
}
停止语
先写到这吧,不论怎样说,打仗qtforandroid,让我劳绩了良多良多,相对不但限于qt和android范畴。
关于iOS开发的学习打个比方就像把汽车分解最底层的原料有塑料钢铁再用这些底层的工具造出来发动机座椅最后再加上写螺丝胶水等把汽车就拼起来了iOS基本都是英文的资料 |
|