您的位置 首页 数字

Symbian 入门

这学期专业实践要做一个关于Symbian S60的手机软件,所以我选择了CarbideV1.2 OE

这学期专业实践要做一个关于Symbian S60的手机软件,所以我挑选了CarbideV1.2 OEM和S60 SDK 3rd FP1来作为自己的开发环境,详细的环境调配如下:

1.首要装置Carbide,挑选OEM版别,至于License的话在网上能够查的出来,咱们自己去找,然后会呈现release_notes提示装置Perl和SDK等.

2.装置Perl,挑选activeperl 5.6.1的版别装置,否则会呈现下面的网络上面常见的问题:

运用Carbide用导游新建了Symbian OSC++ Project,挑选3rd Ed. GUI Application模版,依据步 骤树立了工程,挑选Emulator Debug,编译时呈现下如问题:

make[1]: *** No rule to make target `\Symbian\9.2\S60_3rd_FP1_2\EPOC32\BUILD\Symbian\carbide\workspace\test\group\TEST\WINSCW\TEST.WINSCW’. Stop. test line 0这样的问题,假设挑选5.6.1 的话就不会呈现上面的问题。(所以软件不是最新版别便是最好的阿!).

3.装置SDK最好在他的默许目录,而且这几个都是最好在一起,我挑选的是C盘装置软件和操作体系,给了35G的巨细。D盘存取数据。所以这些我都是装置在他的默许目录下面。Carbide和Perl 装置在C 盘program files.SDK 就直接装置在了C盘上面了。这样的话底子上就差不多了。

4.翻开Carbide,要将作业的空间选取在和自己装置carbide的盘符相同的盘下面。否则的话会呈现下面的过错:

WARNING: EPOCROOT does not specify an existing directory

BLDMAKE ERROR: Directory \Symbian\9.2\S60_3rd_FP1\EPOC32\ does not exist

上面的是我在装备Symbian开发环境时分的一点经验之谈,期望能够对咱们有一些协助,也欢迎咱们给与指导,给我这个菜鸟一些协助,在此先感谢咱们了。

PS:我是一个菜鸟,也是刚开端学习Symbian开发相关,所以对Symbian开发不太了解,之所以在这儿写博客是我发现里边有许多Symbian开发的高手,所以期望咱们能够给与我一些协助,在此再次感谢了!!~-~

—————————————————————————————————-

开发软件来编译程序,编写程序。即Integrated Development Environment (IDE) ,它包含修正器,编译器和衔接器。

引荐用Nokia’s Carbide.c++ Express Edition (based on the Eclipse IDE)或许Visual Studio .NET 2003。

需求软件开发东西包,即Software Development Kit (SDK),它答应你写,创立程序为你的手机。

对N73,需求S60 2nd Edition FP2version 9.1 introduced a complete break from older versions.

To work on Symbian OS version 9.1 or later, applications must be slightly modified andrecompiled.

不同的Symbian os用户界面user interface (UI)是不相同的。因而要挑选正确的SDK。

• S60 3rd Edition Feature Pack 1 – Symbian OS v9.2

• S60 3rd Edition – Symbian OS v9.1

• S60 2nd Edition Feature Pack 3 – Symbian OS v8.1

• S60 2nd Edition Feature Pack 2 – Symbian OS v8.0a

• S60 2nd Edition Feature Pack 1 – Symbian OS v7.0s

enhanced

• S60 2nd Edition – Symbian OS v7.0s

• S60 1st Edition – Symbian OS v6.1

由于咱们的os是v9.1的,所以需求S60 3rd Edition。

能够在http://developer.symbian.com/main/tools/sdks/s60/index.jsp上下载

下载IDE CodeWarrior Development Studio for Symbian os 3.1(OEM,Professional and Personal)

下载地址为:http://www.forum.nokia.com/info/sw.nokia.com/id/4d2d8611-c490-4f6e-a931-

ea37ba4f040d/CodeWarrior_Development_Studio_for_Symbian_OS_Personal_Edition_Version_3_1.html

装置其个人版,可试用90天。

装置SDK

验证SDK的装置

1、用devices指令设置S60 3rd Edition SDK for Symbian OS for C++ 作为默许的设备

例如:devices -setdefault @S60_3rd:com.nokia.S60

2、到包含helloworldbasic的目录下 默许装置下为cd C:\Symbian\9.1\S60_3rd\S60Ex\helloworldbasic

3、再进到group目录下,该目录下包含bld.inf和helloworldbasic.mmp文件

4、验证编程环境

运转—〉输入cmd—〉输入epoc—〉呈现模仿器则表明装置成功。

注:参看Getting_Started_final.pdf

————————————————————————————————————————-

Nokia依据手机的屏幕巨细和价格凹凸把手机分红了多个系列,现在运用的系列有:Series 40、Series 60、Series 80 和Series 90。60系列

选用Symbian os 6.1,然后又依据手机屏幕的特色对UI做了一些修正,这个被修正了的Symbian就被称为Nokia的60系列渠道。运用60系列的手

机类型包含:Nokia 6670、 Nokia 6630、 Nokia 6260 、Nokia N-Gage QD™ 、Nokia 7610 、Nokia 6620 、Nokia 3620 、Nokia 3660 、

Nokia 6600 、Nokia 3600、Nokia 3650、Nokia 7650、Nokia N-Gage™等。

下面咱们就以60系列为例,介绍SDK的装置进程。

2.1.1 装置SDK

第一步,到Nokia论坛注册,下载最新的SDK。Nokia 网站供给的Series 60 SDK for Symbian OS Nokia Edition SDK最新版别是v1.2,Series

60 SDK for Symbian OS的最新版别是v2.1。下载网址:http://www.forum.nokia.com/main/0,6566,034-4,00.html

第二步,到http://www.activestate.com 网站下载最新的Active Perl Script 装置程序。到http://www.java.com/en/download/manual.jsp

下载最新的J2RE。

第三步:装置SDK,引荐为Symbian开发独自建一个目录,例如d:\Symbian而不是运用C:\program files等这样的目录。

第四步:装置Active Perl和J2RE,装置到默许目录即可。

第五步:检查环境变量设定。翻开体系环境变量tab,然后看看有没有EPOCROOT,假设有的话,把它手动改成“\” 。改完之后应该是这个姿态

的:

EPOCROOT = \

然后,在体系PATH中参加 \epoc32\tools目录以及\epoc32\gcc\bin目录就能够了。

实践上,Symbian SDK底子不必装置,直接把epoc32目录仿制到一个机器上,然后照上述办法设定目录和环境变量就能够了。

2.1.2 装备VC

假设咱们运用的是VC 6.0,咱们要确保体系至少打了SP3补丁,否则体系会有正告提示。假设咱们运用的是VS.NET2003, 咱们就只能装置Series

60 SDK for Symbian OS v2.1,由于Series 60 SDK for Symbian OS Nokia Edition SDK v1.2在VS.NET2003无法正确树立工程。

假设要直接在vc6里创立新项目,要把\Symbian\6.1\Series60\Series60Tools\ Application Wizard目录下的 AvkonAppWiz.awx和

AVKONAPPWIZ.HLP文件仿制到vc6的模板目录C:\Program Files\ Microsoft Visual Studio\ Common\ MSDev98\ Template下。这样咱们就能够

在VC的新建工程中看到Series 60 AppWizard v 1.9这个选项.

填入Project Name 今后,承认。

一路“Next”,一个最简略的Symbian运用程序就树立好了。

假设要将现已树立好的工程导入到VC6.0中,比方咱们将SDK中的比方HelloWorld转化成一个VC6的项目,咱们首要进入\Symbian\6.1\Series60

\Series60Ex\HelloWorld目录。在这儿咱们能够看到,在Symbian中,一个Project一般是按inc, src, group等目录安排,group目录里一般放

的是项目文件,所以编译时要先到这儿。用指令提示符方式进入方才说的那个目录下,然后履行:

bldmake bldfiles

这个指令会在group目录下生成一个abld.bat的批处理文件,而且会在\Symbian \6.1\Series60\Epoc32\BUILD下生成\Symbian\6.1\Series60

\Epoc32\BUILD\SYMBIAN\6.1\ SERIES60\SERIES60EX\HELLOWORLD\GROUP这个目录,并在最底层目录下生成一堆 .make文件。

然后,咱们在同一个目录运转方才生成的abld.bat:

abld makefile vc6

这样就会主动生成vc6的dsw文件,方位在\Symbian\6.1\Series60\Epoc32\BUILD\ SYMBIAN\6.1\ SERIES60

\SERIES60EX\HELLOWORLD\GROUP\HELLOWORLD\WINS。然后咱们就能够在VC6种翻开这个Symbian工程了。

2.2 编译

咱们能够直接运用SDK供给的东西编译Symbian 工程,也能够运用VC6供给的集成环境来编译转化过的Symbian 工程。编译的成果存放在

\Symbian\6.1\Series60\Epoc32\ Release\wins\UDEB\Z\SYSTEM\apps目录中。

2.2.1运用SDK供给的东西编译Symbian 工程

咱们在上一节的那个方位持续输入:

abld build wins udeb

这个指令会编译咱们的程序,最终在\Symbian\6.1\Series60\Epoc32\Release\wins\UDEB目录下生成咱们的helloworld,然后咱们能够从开端

菜单里运转模仿器的debug版,在模仿其间就能够运转helloworld了。

2.2.2 运用VC6编译Symbian 工程

咱们直接翻开运转abld makefile vc6后生成的dsw文件,VC主动装载转化过的工程。按F7便能够直接编译工程,编译成果相同放在

\Symbian\6.1\Series60\Epoc32\Release\ wins\UDEB目录中。然后咱们翻开模仿器debug 版,就能够看到咱们编译好的工程了。

2.3 打包

咱们以SDK 1.2供给的HelloWorld为例,制造能够在手机中装置的.SIS文件:

2.3.1.检查程序

首要,在指令行格局下,进入HelloWorld工程mmp文件地点目录,输入bldmake bldfiles和abld build wins udeb,然后翻开模仿器,检测程序

有无过错。

2.3.2.编译工程

在程序无过错后,在指令行输入abld build armi urel 。履行这个指令之后会在目录d:\symbian\6.1\series60\epoc32\release\armi\urel生

成HELLOWORLD.APP和HELLOWORLD.RSC两个文件。

2.3.3.树立.pkg文件

在d:\Symbian\6.1\Series60\Series60Ex\helloworld\sis 用记事本树立或许修正工程的pkg文件,内容如下:

; HelloWorld.pkg

;

;Language – standard language definitions

EN

; standard SIS file header

#{HelloWorld},(0x10005B91),1,0,0

;Supports Series 60 v 1.2

(0x101F8202), 0, 0, 0, {Series60ProductID}

;

d:\symbian\6.1\series60\epoc32\release\armi\urel\HelloWorld.APP-!:\system\apps\HelloWorld\HelloWorld.app

d:\symbian\6.1\series60\epoc32\release\armi\urel\HELLOWORLD.rSC-!:\system\apps\HelloWorld\HELLOWORLD.rSC

其间,前面d:\symbian\6.1\series60\epoc32\release\armi\urel\HELLOWORLD.rSC是要打包装置的文

件,!:\system\apps\HelloWorld\HELLOWORLD.rSC是装置的方针方位。在其间要留意的是,咱们在方针方位顶用“!”替代了实践的盘符。

这样做得优点是在用户装置的时分,手机体系会提示用户挑选要装置的方位,这就给了用户更大的灵敏度。别的,在Symbian 体系中,装置的

运用程序默许方位是“!:\system\apps ”。

修正好pkg文件后,保存至相应目录。

2.3.4.打包程序

在指令行中,转至pkg文件地点目录,运转指令makesis HelloWorld.pkg。之后咱们就在同一目录下得到了打包好的.sis文件。

2.4 手机测验

将打包好地.sis文件上传至手机中,然后在手机的运用程序办理器中就能够看到咱们打包好的文件。挑选“装置”指令,体系会提示用户要安

装的方位,挑选装置方位后,咱们制造的运用程序就装置到手机中了。

咱们回到手机的主菜单,就会发现新装置的HelloWorld 运用程序。翻开运转,成果和在模仿器中看到的底子是相同的。

———————————————————————————————————————

第一篇:Symbian UI 程序结构

Symbian UI 程序的结构底子上是共同的。咱们只需学习一种简略的结构就能够进行大部分的Symbian开发了。我这儿先介绍一个概念。

1.1 MVC 架构

Symbian 底子上运用MVC架构来树立控件。Symbian UI程序规划首要考究的也是怎样运用控件。而No kia没有做好的一个方面便是有关UI

Control的协助太少了。SDK供给的协助里边底子就没有资源文件的写法。这一张里边我会介绍一些控件例如Dialog,Text Listbox等等资源文

件的写法。一起也会奉告咱们应该到SDK的哪里才干找到这些资源的描绘。

可是首要,我先介绍一下MVC架构。MVC并不是个新东西。他是Model – View – Control的缩写。在曾经smalltalk中就现已开端用了。其首要的

主意是在结构类的时分把显现,操控以及模型分隔。Symbian对其作了小的改动。在Nokia供给的Series 90控件组(便是CKON,今后我再提CKON

的时分咱们要知道指得是S90的控件)中Model首要用来存储数据,以及封装对数据的操作。也便是关于方针实体的操作。View当然是担任显现

。Control被笼统成一个或多个纯虚类(Mixin)其它方针经过重写虚函数来得到方针内部的状况以及操控方针。Series 90的Text Listbox类

CEikTextListBox很好的阐明晰这个构架。比方你能够调用CEikTestListBox中的Model()函数得到一个Model的指针,然后你就能够拜访其间的

CDesArrayFlat数组了。

1.2 Symbian的工程文件

1.2.1工程引导文件bld.inf

这个东东其实便是一个脚本,它奉告Build环境在做Build之前需求预备或知道一些什么东西。最一般的

一种写法是:

PRJ_MMPFILES

project.mmp

这是奉告Build环境:你立刻要处理的工程文件姓名叫project.mmp。咱们假设做比较杂乱的程序或许需求一起Build一切的库,那么就在这儿把

你一切需求Build的工程都列出来:

PRJ_MMPFILES

project.mmp

project_lib1.mmp

project_lib2.mmp

别的的一个常用的符号是PRJ_PLATFORMS这个东东奉告编译环境,以下的这些渠道(Targets)是需求编译的。你能够在这个符号的下一行列出

需求的渠道例如:

PRJ_PLATFORMS

WINS ARMI WINSCW

或许直接用

PRJ_PLATFORMS

DEFAULT

留意,假设你不作PRJ_PLATFORMS这个符号其效果等于PRJ_PLATFORMS DEFAULT,所以这个不是有必要

的。

第三个常用符号是PRJ_EXPORTS这个东西奉告编译环境在编译之前需求把哪些文件先仿制到指定方位。我举个简略的比方咱们就知道什么意思了

。比方你的工程中需求include一个第三方的*.inl的文件,那么假设编译之 前这个文件不存在就会编译不过。你能够这么写:

PRJ_EXPORTS

.\nk_set.inl \epoc32\include

那么在你编译的时分,一个Perl脚本会先把你工程目录下的nk_set.inl文件仿制到\epoc32\include目录下,然后再 编译工程。

大大都工程只需用这三个符号就能够了。还有一点小技巧这个bld.inf文件中是能够写#if #else 等等东西的。

比方:

#if defined(WINS)

….. 留意没有{}

#else

…..

#endif

———————————————————————————————————————

Avkon Series60 extensions and modifications to Symbian’s Uikon and other parts of the Symbian OS Application Framework

Symbian中的运用程序一般分为两个部分,engine和UI,如此的区分增加了可维护性和灵敏性,engine就好象是程序的中心,它首要处理运算和

数据,而UI(应该是User Interface)首要处理数据的显现和一切行为(操作行为应该是)。

engine不谈,它是程序起效果的魂灵,这个是因程序而异的,咱们来看运用程序外观,它能够分为三种体系结构:

一、传统的symbianOS操控体系结构

二、依据对话框的体系结构

三、视图体系结构

看看好象跟MFC搞的似的,也有个View和Dialog,不过也是Symbian便是用C++写的,面向方针特性非常好。

运用什么样的界面取决于程序和界面布局的需求,就不多说了。仅仅不论你运用哪种,都是从一个基类承继而来的,就好象是CView相同。

[传统SymbianOS运用程序的体系结构]

传 统意义上,SymbianOS运用程序是在CCoeControl类的根底上派生出咱们自己的view controls,这些都存放在运用程序的 control stack中

,也便是咱们运用程序的视图。这些controls会依据运用程序的需求来创立开释或显现躲藏,以发生相应的操作。

[Dialog体系结构]

假设主体运用是对话框,那咱们更应该运用这样的体系结构,运用dialogs的优点是咱们光能够靠改动resource文件来修正内容和布局,而不需

要从头编译那c++代码。

留意,假设不当心规划,那嵌套的对话框将耗去许多的仓库空间。

别的,假设dialog体系结构被用于首要视图,那主张讲其规划为非模态对话框。(它不独占用户的输入,用户翻开非模态对话框后,依然能够与

其它界面进行交互。)假设你要生成一个主界面对话框,要求是满屏,并供给多页规划,那应该包含如下features:

RESOURCE DIALOG r_dlgapp_main_dialog

{

flags = EEikDialogFlagNoDrag | EEikDialogFlagNoTitleBar |

EEikDialogFlagFillAppClientRect |

EEikDialogFlagCbaButtons | EEikDialogFlagModelss;

buttons = r_dlgapp_softkeys_options_home;

pages = r_dlgapp_main_pages;

}

假设要创立一个对话框应该如下:

void CDlgappAppUi::ConstructL()

{

BaseConstructL();

iAppView = new(ELeave) CDlgAppMainView;

iAppView->ExecuteLD(R_DLGAPP_MAIN_DIALOG);

AddToStackL(iAppView);

}

ExecuteLD()在调用后当即回来,而且对话框有必要要加到control stack中——运用AddToStack函数,由于非模态对话框不会自己处理这些。

[View体系结构]

运用view的运用程序每次只能有一个活动的view,当另一个view要激活时,当时的view就要被开释。当一个view被开释后,所以的菜单,对话

框以及包含的运用都将被封闭。

每 个view都被当作一个运用UI对待,它有必要供给一个Id()函数以便为体系所标识,它也要重载DoActivateL(),DoDeactivate

(),HandleForegroundEventL(),HandlCommandL()和HandleStatusPaneSizeChange() 函数以处理各种作业。

下面一个个的看

DoActivateL()

当客户端要求你的view激活时,它就要被调用。 client或许发送音讯参数给你的view,假设你的view现已是激活了,那只需当client明确要求

再次激活时才被调用,所以你的 DoActivateL()完结得敷衍这种状况,ie现已激活了view。假设你不计划显现view或许你的view不想处理任何

音讯,那一个简略的检查 和return即可。

DoDeactive()

这个函数当你的view被刊出时调用,view被刊出时一般有两种状况:一是你的运用程序要退出了,二是相同程序里另一个view要被激活。这个

函数很重要,咱们可不能忘记了:)

HandleForegroundEventL()

这 个函数首要是在你的view被激活时调用(即在DoActivateL()和DoDeactivate()之间被调用)。当你的view在前台时,它将是

HanleForegroundEvent(ETrue),当你的view移出前台时,它将为HandleForegroundEvent (EFalse),只需当时台状况的确改动时这个函数才会

被调用。

HandleCommandL()

当view菜单发生一个指令后本函数将被调用。

HandleStatusPaneSizeChange()

当client的尺度由于status pane而改动时,本函数被调用了就。

下面是一个view在承受作业的典型调用次序

1.DoActivateL()

2.HandleForegroundEventL(ETrue)

3.HandleForegroundEventL(EFalse)

4.DoDeactivate()

其间一对HandleForegrounEventL在view被激活的进程中会发生屡次调用。

而DoActivateL()在DoDeactivate()被调用前或许会被屡次调用。

View Resources

假设你要运用view来显现pages,那仅有的途径是创立出自己的AVKON_VIEW资源,里边有自己的CBA和菜单,把这个资源的id传递给view的

BaseContructL()函数即可。

RESOURCE AVKON_VIEW r_viewapp_view1

{

hotkeys = r_viewapp_hotkeys;

menubar = r_viewapp_view1_menubar;

cba = R_AVKON_SOFTKEYS_OPTIONS_BACK;

}

留意假设没有给定的menubar资源,那就会运用确省的体系menubar

Construction

下面这个例程是用的AppUI object’s ConstructL来结构出view的,运用了AddView来挂号,最终把第一个创立的view做为缺省的view了:

void CMyViewArchAppUi::ConstructL()

{

BaseConstructL();

CMyViewArchAppView1* view1 = new(ELeave) CMyViewArchAppView1;

CleanupStack::PushL(view1);

view1->ConstructL();

AddViewL(view1); //Add view1 to CAknAppUi; transfers ownership

CleanupStack::Pop();

CMyViewArchAppView2* view2 = new(ELeave) CMyViewArchAppView2;

AddViewL(View2); // transfer ownership to CAknAppUi

CleanupStack::Pop();

CMyViewArchAppView3* view3 = new(ELeave) CMyViewArchAppView3;

AddViewL(View2); // transfer ownership to CAknAppUi

CleanupStack::Pop();

SetDefaultViewL(*view1);

…….(more code)

要让view发挥效果(留意,一个view自身是没有绘图才能的),它有必要具有得到一个从CCoeControl派生的containers,比方

class CMyViewArchAppView1Container: public CCoeControl, MCoeControlObserver

下面这个例程将展示编程者自己的CAknView派生类

class CMyViewArchAppView1: public CAknVIew

{

…..

private:

CMyViewArchAppView1Container* iVIew;

}

咱们能够看出App里发生了View,View类中有咱们有必要的Container.

当时激活的view在HandleCommandL()处理指令,这些是自界说功用键和菜单所生成的指令。

void CMyAppView1::HandleCommandL(TInt aCommand)

{

switch (aCommand)

{

case EMyAppCmdSwitchView:

AppUi()->ActivateLocalViewL(KView2Id);

break;

case EAknSoftKeyOk:

{

……

break;

}

case EAknSoftKeyBack:

{

((MEikCommandObserver*)AppUi())->ProcessCommandL(EEikCmdExit);

break;

}

default:

AppUi()->HandleCommandL(aCommand);

break;

}

}

Local View Switching

假设你要切换view,你得供给view的UID

//Now switch the view to view2

iAvkonViewAppUi->ActivateLocalViewL(TUid::Uid(2));

事实上,每个view都有自己的菜单体系,假设你要运用它,应当在AVKON_VIEW资源结构中设置,前面现已讲过了。

而且不论怎样说,假设要运用体系菜单,它的内容在切换之前是必定要更新一次的。

//Switch to a new menu system for the new view

iEikonEnv->AppUiFactory()->MenuBar()->SetMenuTitleResourceId(R_MY_VIEW_ARCH_APP_VIEW2_MENU);

//Now swtich the view to view2

假设要进行长途的视图切换,那就要调用CCoeAppUi::ActivateViewL()函数,并传递了一个包含方针运用程序UID和方针视图UID的TVwsViewId

Leave recovery

Avkon 视图体系结构在DoActivateL()退出时会有个主动的回复机制。体系会调用DoDeactivate()在当时view离去时,回复前一个 view,并把

用户带到之前他们地点的当地。假设程序并没有前一个view的存在,那它就会退出,假设程序前个view便是当时的view(也便是说他们 是重激

活的),则运用程序会企图康复缺省的view.

说了这么多,那咱们在什么状况下选用适宜的体系结构那?下面的内容将会有所协助。

运用传统的SymbianOS体系结构,你要花费许多的时刻研讨代码是怎样作业的,但大部分交互和过错处理的引擎代码都是现成,能够下降你的开

发难度。

Do you have an acyclic graph shaped navigation structure?

假设你视图程序中的navigation能够as an acyclic gragh,那最好运用dialog体系结构。

Are all the application screens dialog like?

假设你的运用程序想运用对话框,那主张你运用dialog体系结构,留意假设要有一个挑选列表,那最好写成包含在dialog中的挑选列表。

Does the application have multiple views or modes, which deal with different sorts of data at the top level?

假设是这样,那最好运用传统或view体系结构。

Do external applications need to switch to different views of your application?

假设是选用view体系结构写的程序,那它必定支撑多个不同的view,而且是外部程序能拜访的。假设你从头开端写一个运用程序,那主张你使

用view体系结构,

否则给我看看有没有现成的代码可利用,不要一味的傻写呵呵。留意,假设一个外部程序运用的显现页面是你的程序所供给的,那你应该在DLL

中处理这个显现页,这个DLL应该是外部程序所能拜访的。

Can all of the applications views be exited without loosing user data?

运用view体系的程序有必要有才能处理因外部程序而引起的views的开释。假设程序不能主动的开释这些view,那就要考虑其他两种体系了,要么

运用view体系as a message passing system,要么让app UI在传统体系中办理view。

Do external applications need complex interactions with the data in your app?

假设外部程序和你的程序有许多的数据交互,那你最好挑选client/server体系。它将减小view的运用量。许多现有的杂乱运用,如短信,web

以及通讯录都运用这样的机制,这是个很好的设想,总比要重写他们要好:)

Is there only a single complex main view in the app?

假设是这种状况,那仍是运用传统的体系。

一些比方>

这儿给出一些假象比方的处理方案。

App launcher

这种程序能够独自运转而且能切换到其他程序,它只需一个view ,而且不承受外部程序的拜访,假设这样会中止它。这样的程序不需求音讯的

传递或外部程序需求的views.

Fast swap window

一个在运转时刻的弹出窗口,这是一个睡觉的弹出对话框其实,它没有状况。

Email app

电 子邮件程序能够读或写电子邮件。这个程序有外部运用views,内部可切换的views,并能做中止操作。Notifier信息能奉告程序显现一个新

的信 息给用户,所以该程序要有处理此恳求的机制,即便在做其他作业时。修正框能够做为其他程序的view显现,运用DLL方式,咱们就能够

做到外部程序的调用 自若。SymbianOS的messaging程序便是一个client/server机制能够在其他程序中被调用。当然要完结内嵌在外部程序中

有许多工 作要做的。当你在写邮件时,很或许又收到新邮件的同志,这个时分新邮件是做为一个嵌套的对话框似的组件显现在里边的,留意,

做这个作业时要特别依靠 inter-application interaction model。

Contacts app

通讯录程序答应进行通讯录的显现、修正和挑选。挑选后的成果能够做为其他程序所用。留意它不能因外部view的切换而中止。

经过一个外部程序可拜访的dll,通讯录就能够被外部程序所拜访。程序自身并不需求views,所以最好运用传统的体系结构编写,而用dialog

敷衍一切的修正窗口。

web browser

web浏览器能够做为单一的web上网东西,也能够内嵌在其他的文档中。web浏览器能够经过外部程序能够拜访的dll来供给一个UI control,但

并不给外部供给可用的全屏运用。它有必要能够敷衍外界的拜访,比方说敷衍在点击mail衔接后编撰电子邮件的进程。

主体程序首要是用传统的体系结构,也能够选用view体系来敷衍拜访页面的需求。

Settings

咱们要关怀的是大局设置和特定运用程序的设置。他们不是一回作业。经管他们或许同享一个库,实践上他们互不相干。

设置程序并不需求为外部的拜访做什么处理供给什么界面,因而他的编写很简略,用传统的或许依据dialog的体系都能够。而部分设置要留意

有必要当心对待外部或许呈现的中止,而且他有或许做为一个模态dialog而处理。

Telephony app

电话号码簿程序并不供给外部view,但他有必要要处理外部资源的恳求。有时分直接用传统的体系去写即可,大部分的外部交互能够经过ETEL

Server.

[运用程序的发动]

从CEikApplication派生的类CAknApplication,他有几个有必要重载的函数:

PreDocContructL()

OpenIniFileLC(RFs aFs)

PreDocConstructL,首要是处理现已结构好的运用程序实体是否正确预备好了。假设现已预备好了,那运用程序能够切换到实体上。留意,这

个函数只检查非内嵌程序。

一般,ini文件并不被series60所支撑,假设要处理,那就要强制性的调用CEikApplication::OpenIniFileC

[BASE CLASSES]

CAknDocument

这个类是做为运用程序文档的基类预备的。用这个函数拜访文档能够不必初始化。这个是拜访Avkon运用程序的比较好的途径。

CAknAppUi

一切的Avkon运用程序有必要从这个类派生。

这个类支撑下面几个特定运用函数:

KeySound support

Accessories for CBA and StatusPane

TextResolver-Avkon-specific error reporting from CAknAppUI::HandleError()

Avkon view architectrue integration

Control dumping – Debug feature

CAknViewAppUi

一切的视图结构有必要由此派生。

《S60_Platform_Application_Framework_Handbook_V20_en.pdf》,其间有些翻译不甚恰当,不过底子上表达了原版的意思。

——————————————————————————————————————

1、开发文档不是很完全,尽管每个api都能找到阐明,但底子上仅仅很简略的介绍。

完结某个功用依据sdk中的文档,底子上不或许完结。有必要寻觅相应的demo和其他的源代码来参阅。

2、中文材料很少,底子都是英文,关于国内的开发人员来说,这又是一道坎。

3、有必要留意内存的操作。比方PushL 和 Pop等等,一些Symbian中特有的机制需求熟练把握。

4、多线程支撑不是很好,多线程中发动的函数有必要为静态的或许大局的,

就这点就给一些需求多线城支撑的solution带来了许多不便当或许底子不能完结。

5、把握了整个Symbian的framework的底子原理之后,整个机制仍是比较明晰明晰的。重要的当地是AppUI和View和Container这三个类。

6、www.newlc.com是一个不错的技能网站。强力引荐。

7、一般www.forum.nokia.com上都会有相关的比方demo能够下载,仅仅比较粗浅。

8、留意rss文件中资源的界说和程序中ui控件的结合,很简略犯错无法发现。

9、mmp文件的修正之后,有必要要从头生成项目文件,否则会导致link 2001之类的过错。

—————————————————————————————————————–

在symbian中,用RThread来操作线程,一个RThread方针代表一个线程的句柄。常用RThead方针来创立或操作其他线程。 RThread的基类是

RHandleBase类,该类封装了句柄的行为。RThread,RProcess,RMutex和RSession-Base都承继自RHandleBase。

创立一个线程

/* Name of the new thread */

_LIT(KThreadName, MyFirstThread);

/* 下面的函数是线程即将履行的。 参数parm是要传递给线程的数据,它的类型为TAny*,适当标准C中的void* 指针 */

TInt CThreadExampleAppUi::ThreadEntryPoint(TAny* param){ TInt* para = static_cast(param); *para = 1; return 1;}

/* 创立一个归于当时进程的线程,并翻开句柄. */

TInt res = iThread.Create(KThreadName, ThreadEntryPoint, KDefaultStackSize, NULL, iVariable);

/* 线程被创立今后进入等候状况,并不能当即履行. 假设要线程履行,需求调用它的Resume办法*/

iThread.Resume();

中止、删去一个运转的线程。能够调用 Suspend() 来中止一个线程. 但它依然存在,能够调用 Resume()来持续.假设要完全删去一个线程,

可调用Kill或Terminate。假设进程的主线程被删去,那么程序也会被中止。

———————————————————————————————————————

在symbian os上运转的四种软件

运用程序

服务

引擎

内核

symbian体系运用活动方针与客户-服务器对作业处理体系进行了优化

硬件资源:

一个cpu,32位arm

一个rom(只读存储器),里边有操作体系与内建的中间件和运用程序

ROM盘被映射到z:盘,一切的文件都能够经过Z:盘拜访。

体系RAM.体系RAM用于两个方面,一是被当时活动的程序和体系中心运用,另一个是当成”C”盘的磁盘空间。这两个部分的巨细是改动的,不行

以保存某个的巨细。由于RAM一般只需8MB到16MB,所以内存或许用完,因而常常呈现内存越界过错或是(写文件时)磁盘已满过错

IO设备,包含带数字笔输入的触摸屏,键盘,记忆卡(被当成D盘),rs232串口,红外口,蓝牙。

电源,包含电池与外接电源

symbian os与pc体系的差异如下:

资源约束:cpu太慢与太少内存

没有硬盘,不能运用写到硬盘的虚拟内存,不能确保有满足的空间保存程序或是数据文件

电源条件严厉.

symbian软件环境如下:

server | server| Application| Application | Application Dll

| | +————–+————- boundary

| | | |

| | | Enghine | Engine

——–+———+————+————–+————– Privilege

boundary

Kernel

kernel作业在高等级,办理机器一切硬件资源。对其它软件模块供给拜访这些硬件资源的接口

其它运用程序作业在用户方式

上面假设了解一般操作体系如linux的话,那跟一般操作体系没有差异

运用程序是一个有用户界面的程序,在独立的进程中运转

这与一般操作体系也没有差异

服务是没有用户界面的程序.服务办理一个或多个资源,并供给api,让客户能够拜访它的服务.服务的客户能够是一个程序或是其它服务.每个服

务也运转在独立的进程空间中。

在symbian中,运用服务的方式供给类似其它操作体系上用驱动程序或是内核程序供给的功用。如文件体系的拜访也是客户/服务类型的。(微内

核 )

引擎是一个运用程序中操作数据而不是与用户交互的部分.一般你能够把一个程序分红引擎部分和一个GUI部分,多部symbian内带的程序都是这

样做的。

一个运用程序引擎能够是一个独立的代码模块或是一个独立的dll,或是几个dll.

引擎和运用程序间的鸿沟是模块或dll的鸿沟。

所以在symbian中有四个组件类型与三个鸿沟类型。dll或是模块组件对穿插引证来说很便当。它们使体系模块化与坚持封装。

权限鸿沟对穿插引证比较费资源,可是确保体系对用户太程序躲藏内核与设备

进程鸿沟是一切的穿插中最贵重的,它们确保在ram中分隔每个程序

可履行文件的格局

在symbian中有两品种型的可履行文件:

exe,每个程序都有一个主进口E32main()(看上面的比方),它在独立的进程中运转

dll,供给多个进口,由体系或是已存在的线程(进程)调用

有两品种型的dll,

同享库dll,为一个或多个程序供给固定的api,这些dll大都后缀是.dll,当程序发动时就被读到内存中。

多态dll,这些dll完结笼统的api,如一个打印机驱动,socket协议或是一个运用程序。它们的扩展名多不是.dll,而是.prn或.prt或.app等。它

们从与dll相关的类承继,并一般只需在程序需求它们时才读入。

从技能上看起来与一般体系上动态库的静态载入与动态载入没有差异

可是从功用上看就不相同了,一种是完结某种特别功用的,从某个相关类承继的dll,另一个是一般dll

代码履行

假设程序代码在rom上,则直接履行,否则需求读到ram中(与一般操作体系不同,一般操作体系都需求读到ram中

不能直接在硬盘上履行)

可履行代码包含三品种型的二进制数据:

程序代码

只读静态数据

可写静态数据

在symbian中对待.exe与.dll是不同的

由于.exe是不行同享的,假设它在ram中履行,那与一般pc体系没有差异,假设在ram中履行,那它在ram中为可写静态数据分配内存

而.dll是同享的,当dll初次读入内存中时,它被分配到一个特别的地址,第二个线程需求这个dll时它只需拜访现已存在的这份copy就能够。

在一切运用它的进程中dll的地址都是相同的。symbian体系维护一个引证计数,当没有其它线程引证时才将它unload.

在rom上的dll像rom上的exe相同直接在rom上履行

为了对dll的巨细进行优化,symbbian进行如下操作;

大都体系支撑经过姓名与经过数字拜访dll供给的进口,由于姓名太长,糟蹋空间,所以symbian只供给经过数字拜访,当然在link时能够经过

姓名link.也便是说在.dll中没有姓名拜访办法,在.lib(引导库,引导linker正确的link这个dll,这个是在windows中运用的概念,在win下每

创立一个dll都会创立一个用户引导链接的同名.lib)中有,你的程序link时link的是.lib,link完结后编译器会主动把引证dll的代码变成数字引

假设dll被读到ram,那重定位信息(把dll

load到什么地址)也有必要包含在可履行文件格局中,这个的影响便是你不能把一个在rom中履行的程序放到ram中履行的程序.(rom中履行的多是

oem厂家,所以一般开发者多不必关怀)

大都运用程序有自己有exe来创立进程,其它的程序运用动态库(DL)L的方式,在主服务线程中调用自己的线程

大都gui程序都是多态(polymorphic)dll,有一个主进口点NewApplication(),这个进口点创立并回来一个承继自CEikAppication的方针.这样的

程序被apprun.exe调用,app文件名为参数传入。

电源办理

电源有必要高效运用

在体系现已关机时,确认程序依然能够运转。如闹钤,关机后,到不时依然能够开机

电源忽然关掉时,要害数据应该能够保存

设备驱动

尽管一般不会了解它,可是了解一下仍是很有用的

设备驱动作业在两个等级

第一个是中止服务程序(ISR),ISR有必要很短,而且不能做许多作业,由于它或许在任何时刻呈现,乃至在内核服务中。一般它仅仅告诉设备产

生了中止并设置一个标志,要求内核为第二阶段的处理运转一个推迟的函数调用(delayed function call DFC)

在便当的时分内核调度DFC.DFC能够运用大都的中心api,一般仅仅作业了后向用户线程告诉io操作现已完结

守时器

` 内核支撑真机上64hz的时钟与模仿器上10hz的时钟

时钟中止是最高优先级中止,它能够经过User::After或是RTime::After拜访。时钟中止在关机时中止,所以假设你恳求5s后的守时操作,然后

跑2s,关机,再开机时它也要等3s

内核一起支撑日期/时刻时钟,你能够运用User::At或是RTime::At。这个守时器很精确。在关机时,假设时刻到了,那它会开机,这对闹钟很

适宜。

内存

symbian运用内存办理单元(memory management unit MMU)办理内存

ROM被映射到z:盘,被映射到一个固定的地址。

物理RAM被MMU分在4k的页,每个物理页能够用于:

用户进程的虚地址空间。

内核服务的虚地址空间

ram盘,盘符是c:,ram盘只可经过文件服务进程拜访

假设dll不在rom中,那它被读到ram,dll被读到ram里边后页面符号为只读只读的。

MMU的页面转化表.假设想了解的话学习一下操作体系原理

自在页表

每个进程的地址空间能够分红下面三类:

体系规模的内存,如体系的rom或是读到ram中的dll

进程规模的内存,如进程的.exe映象和它的可写的静态数据

每个线程的内存,包含线程的栈与线程默许的堆(运用线程默许堆的原因仅仅为了进步内存分配与开释的速度,从开发视点来看,它与体系里边

的内存没有差异)。

留意没有交流文件,所以一切的内存都是直接运用。一起,也或许会发生内存不行或是磁盘(c 已满过错

每个线程的默许栈很小,只需12k,所以在symbian开发中,不要放太多东西到栈中,一般方针都是在堆中分配的。

线程创立后,它的栈巨细就不行再改动。

线程能够运用new或是User::Alloc从线程默许堆中分配内存.假设期望从其它堆中分配内存,只能运用new

动态库(DLL)

symbian中dll不支撑可写的静态数据,所以你在里边不或许运用可写的大局变量或是静态变量.

为什么不支撑呢?假设支撑,那每个进程调用这个dll时,都需求为这个进程分配一个独立的堆,而堆最小单位是4k,体系中有许多堆,而且有很

多程序,所以内存消费基金是很大的。所以就不支撑了

这样开发时不是很不便当?由于在dll中有时需求保存自己的状况,进行交互

为了处理这个问题,symbian中引入了线程本地数据(thread-local storage

TLS)概念(检查Dll::Tls

Dll;;SetTls)。可是调用TLS功用比较慢.tls的最大巨细是1.8k 一般这够用了。

文件:

c: flash ram盘

z: rom盘

d: 记忆棒之类的外挂盘

作业处理

作业处理模型如下图:

keyborad |—————————

|interrupt

|

kernel/driver–+-isr/dfc

|

key event

|

|

window serv—–handle key event———–+update window

| |

|key event draw |request

application +—————– handle ———-+

key event

在symbian中运用活动方针(active object)来处理作业

在symbian os中,一切的symbian

os线程都是作业处理器,每个线程有一个活动调度方针,加上一个或多个活动方针来处理从设备或其它程序发过来的作业。

每个活动方针都有一个虚拟的成员函数RunL(),在这个函数里边处理作业。

多任务与抢占式

symbian os完结抢占式多线程。

活动方针用于在单个线程内完结非抢占式多任务

——————————————————————————————————————–

SymbianOS6.X Series60界面的智能手机底子手机结构..

SymbianOS6.X Series60界面的智能手机,在刺进MMC之后,体系一般存在4个逻辑存储驱动器:C(手机自身的用户存储,SX1有4M),D(虚拟

盘,运用闲暇运转内存虚拟的缓冲盘),E(MMC),Z(手机的体系ROM只读)。

4个盘之中,C E Z盘的文件结构迥然不同。而D驱动器是高速的虚拟驱动器,首要用来保存剪贴板、wap缓存、和一些暂时交流文件,一般情

况下,由体系主动调用,与用户联络不多,不作详细介绍。下面我详细的将C E Z三个驱动器的目录结构和功用解说一下。 跟着装置软件的增

多,C和E盘的目录文件会变得纷冗杂乱,咱们抛开一些软件主动生成的非有必要的文件和目录捉住体系的结构谈一些首要的东西:

E盘根目录下:IMAGES SOUNDS VIDEOS目录,望文生义便是保存了图片铃声视频剪辑,这3个目录等效的呈现在C和Z的Nokia目录下,也便是

说把相应类型的文件仿制到对应的目录都能够被体系辨认(Z盘只读在外),举例阐明:midi文件或许wav文件仿制在E:\sounds\digital\或许

C:\nokia\sounds\digital\就能够像Z:\Nokia\Sounds\digital\中固化的音乐文件相同,呈现在情景方式铃声的挑选项目中。

C:\Nokia是个无关紧要的目录,你完全能够删掉它而没有影响,可是这个目录会常常主动生成。原因是,C盘的Nokia目录中有特别的目录:

INSTALL,很显然这个是为了装置软件而设置的。众所周知,Symbian体系的软件是打成SIS压缩包传入手机的某个存储器中(C、E)然后解包安

装的,体系往往在C:\NOKIA\INSTALL目录下保存一个装置副本,以备装置时遇到不行预见的过错(如忽然没电)或许用户中止时能够康复体系

安全,这也便是许多状况下,在空余很大空间的E盘装置软件时,依然呈现“存储空间已满”的原因,坚持C盘有1M以上的空余空间是个很好的

习气。别的不运用体系的manager转而运用SeleQ进行SIS装置也能够防止发生这个副本。

下面以剖析一下结构最为杂乱的体系中心C:\system目录。System目录由十几个目录和若干文件组成:

※APPS目录:该目录下的子目录保存了软件的主体即:用户交互可履行文件.app、 资源文件.rsc、 图标文件.aif 、无界面可履行程

序.exe以及运转所需的其他文件。装置在E盘的软件除了在E:\System\Apps\目录下保存软件主体之外,往往会在C:\System\Apps\同名目录下创

建一些装备文件。值得留意的是C:\System\apps\phone\oplogo保存了营运商的标志,假设该目录保存了97*25的bmp图画,则在待机状况下将以

该图片替代“中国移动”之类的营运商标志(需求从头发动手机);

※BootData目录:体系的发动参数和日志;

※Data目录:极端冗杂的目录,保存了各式各样的数据,简略介绍几个,backgroundimage.mbm壁纸,btstate.dat蓝牙配对信息,

Calender日历,clockapp.dat时刻参数,Contacts.cdb联络人,以及许多软件的装备文件和wap信息;

※favourites目录:收藏夹;

※install目录:保存了悉数的软件装置信息,每装置一个软件,就在该目录下保存一个同名sis文件索引,巨细在几百b到几K不等,假设

删去这个sis文件,在程序办理中就不会呈现这个软件的装置信息,也就无法通进程序办理删去,可是依然能够在apps目录中直接删去软件主体

和装备文件,有必要的话在libs目录中删去相应运转库,在programs目录中删去相应辅佐运转文件,然后完全卸载软件;

※libs目录:保存某些软件运转时需求的衔接库文件,一般由软件装置;

※mail目录:信息目录,结构杂乱隐晦,除了一些短信、彩信、EMail设置文件之外,收件箱、发件箱、草稿箱、发送陈述、附件等等散布

在丛深杂乱的目录之中。值得一提的是,S60的信息概念比较广,短信彩信Email乃至红外蓝牙传输的文件都归于“信息”,因而承受到的红外

蓝牙的文件,保存在mail目录下,而且能够由检查该信息触发相应的“装置”、“观看”、“修正”等动作;

※MIDIets目录:java装备文件;

※midp目录:java程序主体装置在这儿,假设悉数java装置在E盘,C:\system\将不会呈现这个目录;

※Programs目录:保存辅佐运转文件,和一些无界面程序exe、动态衔接库dll;

※Recogs目录:相关目录,里边的mdl文件标识了文件相关。如QuickWord.mdl标识了体系中的doc文件默许由quickword翻开,别的有些mdl

文件会驱动程序运转,如eLoader.mdl驱动了miniGPS、ExtendProfile等ePsint公司开发的软件,没有这个mdl文件,以上两个软件不能主动加

载;

※Schedules目录:望文生义,保存了日程安排;

※SharedData目录:悉数是软件的装备文件.ini,对用户效果不大,可是能够经过修正其间的某些数值和途径然后使有必要装置在C盘的软件

(多半是7650的软件,它没有mmc)装置到mmc;

※Temp目录:暂时文件。

E:\system目录结构与C:\system底子共同,不同的是,少了intsall目录。

Z:\system比之C:\system愈加巨大杂乱,它保存了体系的悉数自带程序、资源文件、硬件驱动、字体字库、国际化设置和初始参数设置。

在待机状况下输入*#7370#,将初始化手机,底子进程便是清空C盘,仿制Z盘某些内容至C。某种程度上说Z是体系的初始备份。(新手机的第

一幅待机图就保存在Z:\system\data\apac.mbm)

关于途径问题。由于三个盘的system目录结构是类似的,所以同名途径所起到的效果相同,比方E:\system\recogs目录下的相关文件相同

能够起到相关效果,libs等目录类同(有些状况下将C的内容移动到E相应途径中,需求在C:\system\SharedData\对相应的ini文件进行修正)

,而在E(C):\system\下树立Fonts目录则能够参加新的体系字体。只需install目录仅仅在C:\system\下才有用。

了解S60体系的文件结构,关于咱们运用手机有着很大协助,能够最大极限的获取运转空间、了解过错发生的原因,有意识的防止或许会带

来损伤的操作。本文仅仅对文件结构做了开端的讨论和运用层面上的解说,进一步的研讨能够在西门子和诺基亚论坛的官方文档得到全面回答

。期望有所协助。

———————————————————————————————————

数据类型 描绘

TInt8, TUint8 8位 整数

TInt16, TUint16 16位 整数

TInt32, TUint32 32位 整数

TInt, TUint (32位)整数

TReal32,TReal64 实数

TText8, TText16 字符, 适当于 unsigned char, unsigned short int

TBool 布尔

TAny 适当于void

代码标准

Symbian OS 运用许多代码标准, 运用他们能够增强Symbain 代码的可读性, 有些标准乃至是需求严厉遵守的, 比方类的命名:

Symbian OS的类一共有6种: 品种 比方 描绘

T classes TDesC, TPoint 这个类能够向底子类型相同运用,由于他们一般很小,而且不运用heap所以也没有析构函数

C classes CConsoleBase, CActive 这个类是Symbian运用最多的类,C代表他们从CBase类承继而来, 他们有必要有析构函数由于他们的方针创

建在heap中

R classes RFile, RTimer R代表资源(Resource),它们仅仅一个体系资源的句柄,他们自身被创立在Stack上, 可是他们所运用的资源被创

建在heap上,运用结束需求Close()

M classes MEikMenuObserver 这个类是一个空的接口,运用的时分需求从它承继

static classes User, Math 这个类只需静态函数, 一般都是库函数

Structs SEikControlInfo c – struct

变量命名:

品种 比方 描绘

枚举 EMonday,ETuesday E代表枚举

定量 KMaxFileName K代表定量

成员变量 iDevice, iX i代表成员变量

参数 aDevice, aX a代表参数

部分变量 device, x 部分变量没有固定的标准

——————————————————————————————————-

对Symbian一窍不通,当然只能从根底学起了,或许看一个比方再来看看根底更简略些。而我这人比较保守,便是学不会这种办法,还只能从基

础开端。

Symbian的字符串和描绘符:

TPtrC、TBufC、HBufC 是从TDesC派生而来的详细的描绘符类型。TPtr和TBuf这两个都是从TDes派生来,而TDes又是从TDesC派生而来。因而

TDes在TDesC上加了一些常量便当函数。

TDesC

/ | \

/ TBufCBase TDes

TPtrC

| | \

TBufC、HBufC Tptr TBuf

TDesC和TDes是笼统类。

_LIT它把一个符号和一个文字值联合起来,而且发生TlitC,TlitC的二进制方式与TBuf的二进制方式是相同的,因而能够把TLitC作为TDesC类

来替代。_LIT(he,he); const TDesc hehe = he;

_L发生一个TPtrC,而且不必拟定称号也能够用。 const TDesC he = _L(he);

_L与_LIT的差异就在于,_L需求拓荒暂时的栈区。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/zhishi/shuzi/325024.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部