- 浏览: 3552555 次
- 性别:
- 来自: 大连
博客专栏
-
使用Titanium Mo...
浏览量:38217
-
Cordova 3.x入门...
浏览量:607590
-
常用Java开源Libra...
浏览量:682773
-
搭建 CentOS 6 服...
浏览量:89527
-
Spring Boot 入...
浏览量:402129
-
基于Spring Secu...
浏览量:69759
-
MQTT入门
浏览量:91834
文章分类
最新评论
-
afateg:
阿里云的图是怎么画出来的?用什么工具?
各云服务平台的架构图 -
cbn_1992:
博主,采用jdbctoken也就是数据库形式之后,反复点击获取 ...
Spring Security OAuth2 Provider 之 数据库存储 -
ipodao:
写的很是清楚了,我找到一份中文协议:https://mcxia ...
MQTT入门(6)- 主题Topics -
Cavani_cc:
还行
MQTT入门(6)- 主题Topics -
fexiong:
博主,能否提供完整源码用于学习?邮箱:2199611997@q ...
TensorFlow 之 构建人物识别系统
http://zenborgium.blogspot.com.au/2012/01/how-to-not-to-build-and-structure-large.html
Why to structure application
Well, you could put all source code files in same (root) application directory and everything would work fine. The thing here is ... when application grows, it becomes difficult to find particular file or to know where particular part of application is located if files in it are not organized in some meaningful way (for initial application developer, but also for all developers that will work on application at some time).
That's human nature. If you imagine large number of books, finding particular one can be difficult if they are not organized in any meaningful way. Search for particular book can be accelerated if books were sorted alphabetically. Human will search from left to right for first letter first and then for particular book. If books were sorted vertically in rows by first letter, human could find particular one even more faster because letters are clearly separated.
So, organizing things can be beneficial and the way they are organized is important.
That's why good application structure can be very useful. And not only application structure, but conventions in application also.
Why "NOT to"
The answer is simple. Latest versions of Titanium framework introduced CommonJS standard that brought some new functionality, while changed old. That's why this way of structuring application is no longer good (and won't work in future SDK versions), but similar principles can be translated to new, CommonJS, functionality (and I'll show how).
Basic concepts in my library
To understand application structure that I use, I need to explain some basic concepts that I use. This approach might not suit your needs, but it might give you some directions or ideas how to build your library for Titanium framework or how to structure your own application.
I'm using wrapped Object object as basic component. That component is basically container that has methods like add, remove, get, removeAll and getAll.
View is special component that is wrapper around Titanium UI View component. I wrote wrapper for every Titanium UI component (so, I don't use generic wrapper). Every wrapper can do everything what basic component can do, but beside that it proxies Titanium functionality (for example it adds or removes Titanium UI components in the background) and alters Titanium provided functionality where necessary (workarounds, simpler or enhanced usage, ...).
A good thing about this approach is that you can use this wrappers with native JS functionality without a fear that something will brake because they are native JS objects and not Titanium host objects. Titanium host objects in many cases do not behave like native JS objects and it's dangerous to do anything with them that is not documented. Also, this wrappers provide secure layer in cases when Titanium API changes or brakes (which is not so rare case). If you write code that depends directly on Titanium API, you could eventually end up in rewriting a lot of code. For example, "children" property in recent version was removed from some components. It is not so rare case that we need to get all child components of some component. If you depend directly on Titanium API, you would need to rewrite every part of your application that uses that property.
To simplify functionality of getting particular component, I add its reference as a property.
I use string names to differentiate component instances of same type because it is easier to remember string component name, than integer index position in array of child components. Also, code that uses child component is not dependent on position in parent component so position can be changed without consequences.
I make component for everything that can be reused:
"Toolbar" can again become some kind of component (everything is a component):
This approach is very similar to the one that can be found in EnyoJs (http://enyojs.com/). So, basic idea is to build small components first and then use them to build more and more complex components until whole UI is built. This approach has showed to be very flexible and scalable. Also, once all low level components are built, building higher level components is easy task.
I implemented some things that Titanium framework lacks, like FormView and GridView. FormView is awesome component, basically, every component it contains and that implements "setValue" or "getValue" method FormView can simply use to set its value and to get its value. That way I made that component very generic and it can use literally anything that somehow implements that methods (for example, I use table view in forms, table view is actually collection of data that can be dynamically added or removed). FormView component also implement that methods, so they can be nested.
Basic application would look like this:
Context is window abstraction. It is different from all other components because it is important for memory management. Before 1.8 and especially before 1.7 SDK, Android part of Titanium was unstable and building something complex was mission impossible. Tom Cruise in me made this Context window abstraction that would remove all components and their events when window would close. From what it seemed to me at that time, in some cases, some event listeners were not removed so after window was re-created and re-opened, application would crash. By removing events manually, application would not crash. Also, at that time, many people had memory leak problem that sometimes just could not be solved even with some workarounds that came from community (workarounds that I tried did not work for me). By removing components manually, I did not have memory problems. From what my tests shows, 1.8 has much better memory and event handling and I actually don't use this features any more.
Removing components is easy task when there are wrappers that have "getAll" method, but what about listeners? In Titanium, event system is very basic and don't have much features. Also, Titanium component's "listeners" property was the only way to get list of all listeners, but it was unfortunately removed (partially, at least).
That's why I implemented my own publish/subscribe pattern.
Internally, Events is a container that can register events, publish events, remove (all) events, remove events by particular event type and so on.
In the background, I don't use "listeners" property, but my own container, similar to the one I use for basic component. Events are registered by event type and because of that it is easy to remove all events associated with particular event type. Also, to remove events by some event type, there is no need to store anonymous function anywhere (it is stored internally in "Events" container).
If first argument is omitted, app-level event is created. App-level events are dangerous to use because they they remain in memory all the time application runs and they can potentially create memory leaks, so functionality described above is great to have in cases then app-level events are used (all app-level events can be removed with one statement).
With all this functionality, removing events is trivial task.
Because I don't manually remove events when context closes anymore (starting from 1.8), some extra measures are needed to be done in this implementation to prevent memory leaks. I found that this event system is limited (and IMHO it forces some bad practices) and I have a design idea for new, more advanced, event system that would suit better to usage with my library.
Namespaces and naming convention
To easily name and find components, I split components to different namespaces. I have one root namespace that has subnamespaces.
Concrete implementation of some component would be added to particular namespace where it belongs:
Component name, as every other function constructor, starts with capital letter, while namespace names are lower case.
I made convention that component's code is located in one file and that component namespace name is mapped to file path relative to "Resources" directory and file name. For example Toolbar component's code would be stored in toolbar.js file. Since Toolbar is in "components.ui namespace", toolbar.js file would be located in "Resources/components/ui" directory (FormView component's file name would be form_view.js).
I never put concrete, instantiated component to namespace, because that's a bad practice that might work on iOS, but brakes on Android. Using one component, or even more, adding one component to different windows (even if that doesn't happen in the same time) can have strange side effects. The best approach is to create twin-component whenever it is needed by using function constructor.
To load particular component, I use custom loader:
That method first checks if component is already present in the namespace, if not it includes it:
Every component can have default preferences, which I store to global configuration object (although, code is located in component's file):
which is usually merged with configuration object passed to component's function constructor:
That way other components can change default behavior of some component by passing configuration object modifications as function parameter.
MVC
To separate concerns and to make simple implementation of MVC pattern, I separated how components are defined in the interface and how do they behave (this is actually very useful when one component is used in different situations and therefore they have modified behavior but same appearance).
To do this, I enhanced some Titanium wrappers so they can automatically add other components through configuration object. That is done by convention, configuration object can have special "items" property which defines components that will be automatically added:
This basically is used for "View" part of MVC.
"View" is defined through configuration object defined for every component.
For example, "View" part of ActionBar component would be:
To make Controller part of MVC, View part has to do something. I defined that before in when I described "Events":
Besides interaction, Controller is responsible for component construction, parameter passing, gluing components together, passing data to View, getting data for View and so on. Controller is what gives life to View, View is stupid as it can be (it's just definition through configuration object).
"Model" part is up to you.
I use modified version of Joli ORM (https://github.com/xavierlacot/joli.js/) and Sqlite for database models.
Application structure
Application structure has three main parts: library, components and modules.
In library, there are all common things, like functionality for including components, creating namespaces, events system definition, database ORM and so on.
In components there are all general components that have no specific data in them. That components can be reused in multiple projects. For example, there are UI components (Button, Toolbar, FormView), filesystem component, XML component, ...
In modules there are all project-specific components with data in them grouped into modules and their submodules where necessary (for big modules it's handy to group them into submodules). This components are general components with specific data in them. For example, if Button is general component, specific component would be LoginButton which is Button component with specific title.
View part is stored in "ui" namespace, while Controller is stored in module's root directory. Beside that two, I store models in module's directory also.
Common practice that many people follow is not to separate this two kinds of components (with and without specific data), but I think it is better to separate them. If you mix project specific data with general components, then it will not be possible to reuse them in future projects. By separating them clearly, you can just copy components to new project (or link common library when that functionality become available in TiStudio) and start working on project specific modules.
Translation to CommonJS
I'll show you how I easily translated to CommonJS standard from this namespace-based application structure.
The biggest problem in CommonJS implementation in Titanium framework is that it does not have global variable implementation. As you might have noticed, namespace object in my application is stored in global variable which is accessible everywhere in the application.
Other problem is that CommonJS standard forces specific syntax.
Other things are pretty much the same.
To translate from namespace syntax to CommonJS syntax I had to do two things. First was to use regular expression to replace all this kind of patterns:
to
Second, I had to modify my "Ns.require" method so it does not use "Ti.include", but "require" instead. The trick I used to do that coincidentally was basic idea that I used to solve problem of global variables.
"Ti.include" basically copy-pastes source code, while "require" returns what module exports. The trick here is to simulate what "Ti.include" was doing by using "require" function. That is, I just add module exports to global namespace object. The only thing that needed to be fixed was to "require" this global object on top of each module's file:
And that was it.
That is still not real CommonJS approach, but the thing here was following: on Android, "Ti.include" did not work inside functions (while "require" did when it was introduced), so everything had to be preloaded in the application (there was no way to include file on demand). For large project this was a disaster, I had to wait 10 seconds just to start application. Add 10 seconds of compilation time to that and you'll understand the secret of my high position in Appcelerator's Q/A.
I still don't use CommonJS in real sense, but I am slowly refactoring my application. For example, now I don't store configuration objects in global object, but in module's private variable.
Final words
Although this approach is very nice in many cases, I found it limited in some ways. I miss some things in it, some things would be better if they were made in a different way.
Also, it's not the optimal. When building complex things for mobile devices, it is important to be aware of performance of your code from the beginning. Optimizing server is easy, you just buy more/better hardware. But you can't do that on mobile devices and with application size increasing, micro-optimizations are more and more noticeable (you will never, and not even then, do micro-optimization of server code).
After one year of programming with Titanium I have found two things.
To know how to program with Titanium, you must know JavaScript that is defined by ECMAScript specification (forget your jQuery skills). Basic JS skills are the best investment in your knowledge of Titanium.
After one year of intensive JS programming I have found that I don't know to think in JS (good thing is that now I am aware of that).
Why to structure application
Well, you could put all source code files in same (root) application directory and everything would work fine. The thing here is ... when application grows, it becomes difficult to find particular file or to know where particular part of application is located if files in it are not organized in some meaningful way (for initial application developer, but also for all developers that will work on application at some time).
That's human nature. If you imagine large number of books, finding particular one can be difficult if they are not organized in any meaningful way. Search for particular book can be accelerated if books were sorted alphabetically. Human will search from left to right for first letter first and then for particular book. If books were sorted vertically in rows by first letter, human could find particular one even more faster because letters are clearly separated.
So, organizing things can be beneficial and the way they are organized is important.
That's why good application structure can be very useful. And not only application structure, but conventions in application also.
Why "NOT to"
The answer is simple. Latest versions of Titanium framework introduced CommonJS standard that brought some new functionality, while changed old. That's why this way of structuring application is no longer good (and won't work in future SDK versions), but similar principles can be translated to new, CommonJS, functionality (and I'll show how).
Basic concepts in my library
To understand application structure that I use, I need to explain some basic concepts that I use. This approach might not suit your needs, but it might give you some directions or ideas how to build your library for Titanium framework or how to structure your own application.
I'm using wrapped Object object as basic component. That component is basically container that has methods like add, remove, get, removeAll and getAll.
var component = Component(); var view = View(); component.add('MyView', view); component.get('MyView'); //view
View is special component that is wrapper around Titanium UI View component. I wrote wrapper for every Titanium UI component (so, I don't use generic wrapper). Every wrapper can do everything what basic component can do, but beside that it proxies Titanium functionality (for example it adds or removes Titanium UI components in the background) and alters Titanium provided functionality where necessary (workarounds, simpler or enhanced usage, ...).
A good thing about this approach is that you can use this wrappers with native JS functionality without a fear that something will brake because they are native JS objects and not Titanium host objects. Titanium host objects in many cases do not behave like native JS objects and it's dangerous to do anything with them that is not documented. Also, this wrappers provide secure layer in cases when Titanium API changes or brakes (which is not so rare case). If you write code that depends directly on Titanium API, you could eventually end up in rewriting a lot of code. For example, "children" property in recent version was removed from some components. It is not so rare case that we need to get all child components of some component. If you depend directly on Titanium API, you would need to rewrite every part of your application that uses that property.
To simplify functionality of getting particular component, I add its reference as a property.
component.MyView // same as component.get('MyView')
I use string names to differentiate component instances of same type because it is easier to remember string component name, than integer index position in array of child components. Also, code that uses child component is not dependent on position in parent component so position can be changed without consequences.
I make component for everything that can be reused:
function Toolbar(config) { var view = View({ bottom: 0, height: '10%' }); return view; } ... var toolbar = Toolbar(); toolbar.add('SaveButton', Button({ title: 'Save' }); toolbar.add('CancelButton', Button({ title: 'Cancel' });
"Toolbar" can again become some kind of component (everything is a component):
function ActionBar() { var toolbar = new Toolbar(); toolbar.add('SaveButton', Button({ title: 'Save' }); toolbar.add('CancelButton', Button({ title: 'Cancel' }); return toolbar; }
This approach is very similar to the one that can be found in EnyoJs (http://enyojs.com/). So, basic idea is to build small components first and then use them to build more and more complex components until whole UI is built. This approach has showed to be very flexible and scalable. Also, once all low level components are built, building higher level components is easy task.
I implemented some things that Titanium framework lacks, like FormView and GridView. FormView is awesome component, basically, every component it contains and that implements "setValue" or "getValue" method FormView can simply use to set its value and to get its value. That way I made that component very generic and it can use literally anything that somehow implements that methods (for example, I use table view in forms, table view is actually collection of data that can be dynamically added or removed). FormView component also implement that methods, so they can be nested.
function Login() { var formView = FormView(); formView.add('Content', View()); formView.add('Toolbar', ActionBar()); var textField = TextField({ value: 'iskugor' }); //implements "getValue" and "setValue" formView.Content.add('UserName', textField). formView.getValue(); // returns { 'UserName': 'iskugor' } formView.setValue({ 'UserName': 'anonymous' }); //sets text field's value return formView; }
Basic application would look like this:
//very simplified var win = Context(); var form = Login(); win.add('Form', form); win.open();
Context is window abstraction. It is different from all other components because it is important for memory management. Before 1.8 and especially before 1.7 SDK, Android part of Titanium was unstable and building something complex was mission impossible. Tom Cruise in me made this Context window abstraction that would remove all components and their events when window would close. From what it seemed to me at that time, in some cases, some event listeners were not removed so after window was re-created and re-opened, application would crash. By removing events manually, application would not crash. Also, at that time, many people had memory leak problem that sometimes just could not be solved even with some workarounds that came from community (workarounds that I tried did not work for me). By removing components manually, I did not have memory problems. From what my tests shows, 1.8 has much better memory and event handling and I actually don't use this features any more.
Removing components is easy task when there are wrappers that have "getAll" method, but what about listeners? In Titanium, event system is very basic and don't have much features. Also, Titanium component's "listeners" property was the only way to get list of all listeners, but it was unfortunately removed (partially, at least).
That's why I implemented my own publish/subscribe pattern.
Events.subscribe(button, 'click', function(e) { //do something });
Internally, Events is a container that can register events, publish events, remove (all) events, remove events by particular event type and so on.
Events.subscribe(button, 'CustomEvent', function(e) { Ti.alert('Custom event!'); }); Events.publish(button, 'CustomEvent'); Events.removeByEventName(button, 'click'); //removes all click events Events.removeAll(button); //removes all events
In the background, I don't use "listeners" property, but my own container, similar to the one I use for basic component. Events are registered by event type and because of that it is easy to remove all events associated with particular event type. Also, to remove events by some event type, there is no need to store anonymous function anywhere (it is stored internally in "Events" container).
If first argument is omitted, app-level event is created. App-level events are dangerous to use because they they remain in memory all the time application runs and they can potentially create memory leaks, so functionality described above is great to have in cases then app-level events are used (all app-level events can be removed with one statement).
With all this functionality, removing events is trivial task.
Because I don't manually remove events when context closes anymore (starting from 1.8), some extra measures are needed to be done in this implementation to prevent memory leaks. I found that this event system is limited (and IMHO it forces some bad practices) and I have a design idea for new, more advanced, event system that would suit better to usage with my library.
Namespaces and naming convention
To easily name and find components, I split components to different namespaces. I have one root namespace that has subnamespaces.
Ns = {}; //root namespace Ns.components = {}; //components namespace Ns.components.ui = {}; //components ui namespace Ns.components.filesystem = {}; // components filesystem namespace Ns.events = {}; // events namespace
Concrete implementation of some component would be added to particular namespace where it belongs:
Ns.components.ui.Toolbar = function() { ... };
Component name, as every other function constructor, starts with capital letter, while namespace names are lower case.
I made convention that component's code is located in one file and that component namespace name is mapped to file path relative to "Resources" directory and file name. For example Toolbar component's code would be stored in toolbar.js file. Since Toolbar is in "components.ui namespace", toolbar.js file would be located in "Resources/components/ui" directory (FormView component's file name would be form_view.js).
I never put concrete, instantiated component to namespace, because that's a bad practice that might work on iOS, but brakes on Android. Using one component, or even more, adding one component to different windows (even if that doesn't happen in the same time) can have strange side effects. The best approach is to create twin-component whenever it is needed by using function constructor.
To load particular component, I use custom loader:
Ns.require('Ns.components.ui.Toolbar');
That method first checks if component is already present in the namespace, if not it includes it:
Ti. include('/components/ui/toolbar.js');
Every component can have default preferences, which I store to global configuration object (although, code is located in component's file):
Ns.config.add('Toolbar', { height: '10%', bottom: 0, layout: 'horizontal' });
which is usually merged with configuration object passed to component's function constructor:
Ns.components.ui.Toolbar = function(configuration) { var config = Ns.config.merge(configuration, Ns.config.get('Toolbar')); var component = View(config); return component; };
That way other components can change default behavior of some component by passing configuration object modifications as function parameter.
MVC
To separate concerns and to make simple implementation of MVC pattern, I separated how components are defined in the interface and how do they behave (this is actually very useful when one component is used in different situations and therefore they have modified behavior but same appearance).
To do this, I enhanced some Titanium wrappers so they can automatically add other components through configuration object. That is done by convention, configuration object can have special "items" property which defines components that will be automatically added:
var actionBar = Ns.components.ui.View({ height: '10%', bottom: 0, layout: 'horizontal', items: { 'SaveButton': function() { return Ns.components.ui.Button({ title: 'Save' }); }, 'CancelButton': function() { return Ns.components.ui.Button({ title: 'Cancel' }); } } }); actionBar.SaveButton; //button
This basically is used for "View" part of MVC.
"View" is defined through configuration object defined for every component.
For example, "View" part of ActionBar component would be:
Ns.config.add('ActionBar': { height: '10%', bottom: 0, layout: 'horizontal', items: { SaveButton: function() { return Ns.components.ui.Button({ title: 'Save' }); }, CancelButton: function() { return Ns.components.ui.Button({ title: 'Cancel' }); } } }); Ns.components.ui.ActionBar = function(configuration) { var config = Ns.config.merge(configuration, Ns.config.get('ActionBar')); return Ns.components.ui.Toolbar(config); };
To make Controller part of MVC, View part has to do something. I defined that before in when I described "Events":
Events.subscribe(form.Toolbar.SaveButton, 'click', function(e) { Ti.alert('Username: ' + form.getValue().UserName); //do something with login data });
Besides interaction, Controller is responsible for component construction, parameter passing, gluing components together, passing data to View, getting data for View and so on. Controller is what gives life to View, View is stupid as it can be (it's just definition through configuration object).
"Model" part is up to you.
I use modified version of Joli ORM (https://github.com/xavierlacot/joli.js/) and Sqlite for database models.
Application structure
Application structure has three main parts: library, components and modules.
In library, there are all common things, like functionality for including components, creating namespaces, events system definition, database ORM and so on.
In components there are all general components that have no specific data in them. That components can be reused in multiple projects. For example, there are UI components (Button, Toolbar, FormView), filesystem component, XML component, ...
引用
/components/ui/button.js
In modules there are all project-specific components with data in them grouped into modules and their submodules where necessary (for big modules it's handy to group them into submodules). This components are general components with specific data in them. For example, if Button is general component, specific component would be LoginButton which is Button component with specific title.
引用
/modules/user/ui/login_button.js
View part is stored in "ui" namespace, while Controller is stored in module's root directory. Beside that two, I store models in module's directory also.
引用
/modules/user/models/db/users.js
Common practice that many people follow is not to separate this two kinds of components (with and without specific data), but I think it is better to separate them. If you mix project specific data with general components, then it will not be possible to reuse them in future projects. By separating them clearly, you can just copy components to new project (or link common library when that functionality become available in TiStudio) and start working on project specific modules.
Translation to CommonJS
I'll show you how I easily translated to CommonJS standard from this namespace-based application structure.
The biggest problem in CommonJS implementation in Titanium framework is that it does not have global variable implementation. As you might have noticed, namespace object in my application is stored in global variable which is accessible everywhere in the application.
Other problem is that CommonJS standard forces specific syntax.
exports.ModuleName = function() {}; //or module.exports = {};
Other things are pretty much the same.
To translate from namespace syntax to CommonJS syntax I had to do two things. First was to use regular expression to replace all this kind of patterns:
引用
Ns.components.ui.ComponentName
to
引用
exports.ComponentName
Second, I had to modify my "Ns.require" method so it does not use "Ti.include", but "require" instead. The trick I used to do that coincidentally was basic idea that I used to solve problem of global variables.
"Ti.include" basically copy-pastes source code, while "require" returns what module exports. The trick here is to simulate what "Ti.include" was doing by using "require" function. That is, I just add module exports to global namespace object. The only thing that needed to be fixed was to "require" this global object on top of each module's file:
Ns = require('library/ns');
And that was it.
That is still not real CommonJS approach, but the thing here was following: on Android, "Ti.include" did not work inside functions (while "require" did when it was introduced), so everything had to be preloaded in the application (there was no way to include file on demand). For large project this was a disaster, I had to wait 10 seconds just to start application. Add 10 seconds of compilation time to that and you'll understand the secret of my high position in Appcelerator's Q/A.
I still don't use CommonJS in real sense, but I am slowly refactoring my application. For example, now I don't store configuration objects in global object, but in module's private variable.
var defaultConf = { ... }; exports.ComponentConstructor = function(configuration) { //merge };
Final words
Although this approach is very nice in many cases, I found it limited in some ways. I miss some things in it, some things would be better if they were made in a different way.
Also, it's not the optimal. When building complex things for mobile devices, it is important to be aware of performance of your code from the beginning. Optimizing server is easy, you just buy more/better hardware. But you can't do that on mobile devices and with application size increasing, micro-optimizations are more and more noticeable (you will never, and not even then, do micro-optimization of server code).
After one year of programming with Titanium I have found two things.
To know how to program with Titanium, you must know JavaScript that is defined by ECMAScript specification (forget your jQuery skills). Basic JS skills are the best investment in your knowledge of Titanium.
After one year of intensive JS programming I have found that I don't know to think in JS (good thing is that now I am aware of that).
发表评论
-
VisualUI for Titanium Studio
2014-01-13 09:02 1548VisualUI for Titanium Studio is ... -
Google Auth (OAuth 2.0) for Titanium
2013-03-19 11:49 2061Google OAuth 2.0 for Titanium i ... -
Appcelerator Titanium: Up and Running
2013-03-19 08:40 46Appcelerator Titanium: Up and R ... -
Titanium SDK/Studio 3.0.0 Beta版发布
2012-11-07 09:36 463Titanium SDK/Studio 3.0.0 Beta版 ... -
Titanium SDK 3.0.0 Developer Preview
2012-10-29 16:15 303Titanium SDK 3.0.0 Developer Pr ... -
Appcelerator Partners With Largest Chinese Software Developer Network
2012-10-29 12:01 225(Marketwire - Oct 19, 2012) -Ap ... -
Titanium 3.0 预定10月份发布
2012-09-27 09:12 733Appcelerator CEO Jeff Haynie和 C ... -
Titanium SDK 2.1.3 RC is released – Support for iOS 6
2012-09-21 13:51 241---以下官方原文--- We understand the ... -
国内Ti开发者Winson的CBMVC框架
2012-08-06 15:55 1206目前关注Titanium的开发 ... -
Titanium的MVC框架"Alloy"的介绍
2012-07-18 14:37 4263Alloy(合金)是Appcelerator公司为Titani ... -
TCAD免费考试延长至7月末
2012-07-17 16:09 327Appcelerator延长这次TCAD免费考试的时间到7月末 ... -
TCAD认证考试
2012-07-13 11:31 2581Appcelerator从7/7开始免费开放TCAD(Tita ... -
【转】Appcelerator Cloud Push Notification in iPhone
2012-07-12 08:49 2766Push Notification in iOS Using ... -
【转】Appcelerator Cloud Push Notification in Android
2012-07-12 08:38 2489What is Push Notification? Push ... -
Appcelerator Titanium: Patterns and Best Practices
2012-07-10 10:58 373Appcelerator Titanium: Patterns ... -
Appceleator Cloud Services使用指南(3) - API Reference V1 (chm版本)
2012-05-28 15:22 1871Appceleator Cloud Services API ... -
Appceleator Cloud Services使用指南(2) - 创建第一个应用
2012-05-24 21:57 1810一步一步的创建一个最简单的,使用了ACS服务的应用。 1、新 ... -
Appceleator Cloud Services使用指南(1) - ACS介绍
2012-05-24 10:19 3270Appceleator Cloud Services( ... -
Titanium Mobile基础教程视频
2012-05-23 10:38 639dotinstall.com提供的一套在线Titanium M ... -
Jeff Haynie在GMIC2012表示应用开发者应注意本土化问题
2012-05-22 16:56 3355月10日-11日,2012全球移 ...
相关推荐
### Titanium Mobile API 知识点详解 #### 一、Titanium Mobile API 概述 Titanium Mobile API 是一款由 Appcelerator 公司提供的用于跨平台移动应用开发的强大工具包。该工具允许开发者使用 JavaScript 编写应用...
Titanium Mobile SDK 3.1.0 是一个用于构建原生移动应用的开发工具,尤其针对iOS和Android平台。这个版本的Apidoc是开发者的重要参考资料,它包含了完整的API文档,帮助开发者理解并使用Titanium框架的各种功能。...
TiInspector, 通过 Chrome DevTools调试 Titanium Mobile 应用程序 #Ti 检查器Ti检查器允许在 Chrome DevTools web界面中调试 Appcelerator Titanium 应用程序。工具通过将命令和消息转换为 Chrome 调试协议和 ...
Develop fully-featured mobile applications using a hands-on approach, and get inspired to develop more Overview Walk through the development of ten different mobile applications by leveraging your ...
Titanium Mobile API 1.8.2.chm 内容很好但是英文版的,E不好的童鞋慎下
Titanium Mobile API是用于开发跨平台移动应用的框架,它基于JavaScript,允许开发者用一种语言创建iOS和Android应用。这个框架提供了丰富的API,使得开发者能够访问设备的各种功能,如GPS、摄像头、网络通信等。本...
TiJSPDF, Titanium Mobile 应用程序的JSPDF插件 TiJSPDFTiJSPDF是用于使用JSPDF库生成pdf并在 Titanium Mobile 应用程序中操作它们的Titanium Mobile 应用程序的一种 JSPDF插件插件。这个插件独立于 Titanium 维护,...
TitanTricks, Titanium Mobile的代码示例和组件 TitanTricks自述文件TitanTricks是 Titanium Mobile 项目,充满了可以重用的代码示例和技巧,面向begginers和中级级别用户。android和iOS兼容,但有些示例仅适用于 ...
Android-titanium_mobile.zip,带有javascript的本地ios、android和windows应用程序,安卓系统是谷歌在2008年设计和制造的。操作系统主要写在爪哇,C和C 的核心组件。它是在linux内核之上构建的,具有安全性优势。
ti.mely, Titanium Mobile的Ti.mely 本机定时器 Ti.melyTi.mely 项目提供对Android和iOS计时器的访问。在开始之前* 是在使用这个模块之前,设计用于 Titanium SDK 3.1.1. GA *的iOS和Android本机模块。 如果你需要...
Influence of Titanium Doping on the Structure and Morphology of MgO prepared by Coprecipitation Method,王维,乔学亮,Ti-doped magnesium oxide powders were prepared by a chemical coprecipitation ...
sublimetext-tita, Tita Titanium Mobile/Alloy sublime text 2插件 这个插件不再主动地维护 ***因为我不再使用 st2/st3 。 有人对 fork 感兴趣并维护它?替代插件:...
Building Mobile Applications with Titanium, 这是mobi版,适合knidle等电子书阅读。 详细介绍了titanium框架的使用
适用于 Tizen 的 Titanium Mobile 欢迎来到 Appcelerator Titanium Mobile 开源项目。 Titanium 为 Web 开发人员提供了一个使用 JavaScript 构建跨平台原生移动应用程序的平台。 有关 Titanium 的更多信息,请访问 ...
Titanium Appcelerator API v3.1.3.GA 的环境声明。 var ROWS: number = 10; var children: Array<Titanium> = button.getChildren(); var window: Titanium.UI.Window = Titanium.UI.createWindow({ title: '...
interface to create and manage projects for ECM Tuning V1.61 modified files. After reading the file stored in the ECU memory, all you have to do is upload the file and the software starts a search ...
ASTM B861 ASME SB 861-2010 Titanium and Titanium Alloy
要安装到 haxelib,请运行haxelib git titanium_mobile_externs https://github.com/momer/haxe_titanium_mobile.git <version> haxelib 截至本次更新,最新为 3.5.0-rc1。 使用 externs 很简单,下面是test/Test...