Showing posts with label Development. Show all posts
Showing posts with label Development. Show all posts

Wednesday, May 28, 2014

Building your Own Titanium SDK with Java Script Core

Building your Own Titanium SDK with Java Script Core


Pre-requisite: You are aware of iOS basics and familiar with iOS app development process.

Q.- How does Appcelerator Titanium Work?
A.- Basically is has modified Java Script Core open source framework and created ticore library,
      Which gets added to your build Xcode project when you build your Titanium App for iOS.

So you can use Java Script Core framework directly and create your own SDK, which will work as your want.
Appcelerator has customised this to make a cross platform SDK, because similar JS functionality is provided in android side by V8 JS engine.
So we can use Java Script Core in iOS and V8 in android app development and provide common functionality to create Titanium Like SDK.

Let me show with an example:

Create a Xcode Project, as we create in Xcode. for example say single window application.

My single window Xcode Project:



In the above picture, i have added ANMakePoint and MyButton classes along with all the .js files.

Now the open the project in Xcode:

Add Java Script Core framework

Steps:

  1. After adding the Java Script Core framework, go to your view controller and import the necessary header: "#import ".
  2. After than you need to add one Java Script file, like i did as test.js.
  3. Write your java script function there and save the file.
  4. now come to viewController.m and in viewdidload() function, initialise your JS context and evaluate your Java Script code.
  5. Then you need to get the function form evalauted script using context.
  6. After that you need to call the JS function from Objc code.
  7. Sample Code:

              NSString *myJSPath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"js"];
              NSString *Script = [NSString stringWithContentsOfFile:myJSPath encoding:NSUTF8StringEncoding error:nil];

              JSContext *context = [[JSContext alloc] init];
              JSValue *value = [context evaluateScript:Script];
             // OBJC-->JS calling example
             JSValue *result = [function callWithArguments:@[@5]];


            This is very basic example code for Objc to JS calling.

Now Deep diving a little:

What is bonding between JS and Objc:
Actually Java Script Core framework is designed in  such a way to take care the differences required by two different languages to execute their code.

For Example Objc is a compiled language and code is compiled before execution, while JS is interpreted language and to run JS with Objc we require a VM(virtual machine) to provided interpreted 
environment.

Now This VM and context to execute code is provided by Java Script Core.
Note: VM:- Provide environment.
          Context:- is kind of global java script object for your js file. In web world its Window object.
          JSValue: is java script object or function or any value on which we work upon.

We can have multiple virtual machine and within one virtual machine we can have multiple context as well.
Image:


We can transfer information (object and value exchange) between two context of same virtual machine.

But we can not transfer information (object and value exchange) between two context of two different virtual machine.

Allowed:


Not Allowed: (No information exchange allowed between two context or different VM).


Part1:
Now Objc to Java Script communication happen with the following sequence:
(calling java script function from objective c)
  1. We create a Context. (until required one VM is created by default)
  2. We get our java script code from js file.
  3. Evaluate java script code. (this will return the value of any self executing function -- java script notation.)
  4. From context we get our JS value.(any JSfunction or JSObject).
  5. Call the JS function from Objc using java script core function calling mechanism.
  6. Get the return value from JS function as JSvalue.
Part2:
Now Java Script to Objc communication: (calling Objc method from Java Script)
  1. There are two possible way.
  • Blocks (Objc block can work as a medium to provide functionality of OBJC code to JS).
  • JSExport protocol. (A protocol will work as a class to JS code).
Blocks:
context[@"makeNSColor"] = ^(NSDictionary *rgb){
        float red = [rgb[@"red"] floatValue];
        float green = [rgb[@"green"] floatValue];
        float blue = [rgb[@"blue"] floatValue];
        float alpha = 1.0f;
        
        UIColor *colorReturn = [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha];
        return colorReturn;
    };

Here makeNSColor  will be directly available to java script code as i have added to context(global object).
can be directly called from java script.

var rgb = {
        red:255.0,
        green:67.0,
        blue:70.0
        };
var colorVal = makeNSColor(rgb);

JSExport Protocol:
JSExport protocol works just like normal protocol but provide easy access to Objc code from Java Script.
Sample:

#import <UIKit/UIKit.h>

#import <JavaScriptCore/JavaScriptCore.h>

@protocol MyButtonExports <JSExport>

@property (readwrite,nonatomic) NSString* name;
@property double top;
@property double left;
@property double bottom;
@property double right;

-(id)onClick:(JSValue*)handler;
+(double)makeMyPointWithX:(double)x;
@end

@interface MyButton : UIButton <MyButtonExports>

-(void)clickHappened:(id)args;
@end

Using this approach, property values will be used as a java script getter and setter, while instance method will be used with class instance object and class method will be accessed using class object contained within global context object.

Things to take care: Threading and Memory Management is trivial task in this as java script is a garbage collected language and Objc uses ARC.

Apple has also shared one video in WWDC2013 regarding this communication:
(You need to have Safari and developer account.)

My JSCore sample link: https://app.box.com/s/5d7lfqh7l9o8j23pgt57 (Old code, check new code)
(Note: Its quite unstructured yet, but working. Will update soon with a nice well behaved code.)

Online view: https://app.box.com/s/sgbg3xzrj2idtw5svw1g

(New Code Sample)
Updated Code (Much structured and understandable)
Link: https://app.box.com/s/trr1glmd0dfx9y5hoa4a 

A working well behaved code is available in github under my github repo.
Link: https://github.com/ashishnigam/Team_Dev_Work

(Code is available now, as promised)

Direct Code Link: https://github.com/ashishnigam/Team_Dev_Work/tree/master/iOS_Native/JScoreDemo

JS functions exposed to java script in my sample.

1: createButton();
2: makeNSColor();
3: alert("Happy");
4: button.onClick(callback) {};  
is the instance method exposed. used for binding call backs to JS button object.
5: var callback = function(args){
        alert(args);
        button.tintColor = colorVal;
    };
this the call back exposed which is called on button click.
6: Button.createButton({}); is the Class method exposed, used in "testGeometry.js" which can be tested by commenting JSCoreExport feature and thus commenting the "JSCoreFundamental" method call and uncommenting the "JSCoreExports" method call as below viewdidload call in ANViewController.
- (void)viewDidLoad
{
    [super viewDidLoad];
    [self JSCoreFundamental:nil];
    //  [self JSCoreExports:nil];   
}
7: button.removeButton();
Much more functionality is available, best understood with the help of updated code sample. Checkout from github and test on your own system. Let me know for any clarification.
In sample i have created colours in JS and button object with its click event binding callback function.
Overloaded JS alert function as titanium sdk did.
Changed the label text colour using JS code with its background colour.
The only thing you may need to do it shuffling of commented and uncommented code in viewdidload().

Feel free to ask any query or any suggestions are most welcome. 
This code structure and sample shared is just for conceptual understanding.

Thursday, February 6, 2014

Appcelerator Titanium Module Development for Android

Module Development for Android 

(Using Titanium Version 3.2)



As Appcelerator has already documented well in the android module development part,
So here in this post i am going to write very practical approach which may help you guys for common module initialisation and linking issues.

There are two approaches for module development:

1: Using Terminal and the Eclipse for development and testing.
2: Using Titanium IDE for development, testing and deployment.

Both got their own benefit and drawbacks.

Here i am going to give Module development demo using eclipse, as except module creation in terminal all other things are same.

Terminal Command to create Module:

titanium320.py create --platform=android --type=module --name=<module name> --id=<module.id.reverseDomain> --android=<andorid sdk path>

Explanation:
titanium320.py :  is titanium.py (Titanium SDK version not CLI version) alias in terminal for mac and reference environment variable name in Windows.
name: module name which suits you.
id: module is as per need.
android: Android SDK path. 

Complete Sample command in my machine:
titanium320.py create --platform=android --type=module --name=calc --id=nigam.ashish.calc --android=/Applications/adt_bundle_mac/sdk

This will create a module in the directory you are currently in, in the terminal.

Module Directory structure will look something like this:

The Import the same in Eclipse where after import it should look something like this:


After that just check your build.properties file, it must contain all these properties for proper module build:

titanium.platform=/Users/ashish.nigam/Library/Application Support/Titanium/mobilesdk/osx/3.2.0.GA/android
android.platform=/Applications/adt_bundle_mac/sdk/platforms/android-10
google.apis=/Applications/adt_bundle_mac/sdk/add-ons/addon-google_apis-google-10
android.ndk=/Applications/android_ndk

Now all set, you are ready to build your first module.
Now right click on your build.xml file and go to "Run As" option and click on Ant Build first option.

Result: It will build the module and create module zip in the module source directory, which can be used in titanium application.

Testing on device or emulator:
Right click on your build.xml file and go to "Run As" option and click on Ant Build second option.
it will open a window where on little bit downside scroll, you see a screen like this:


Now you can choose to run on emulator or device:

This will be your screen after selection you can choose both as well but generally not required.

After that hit enter or click ok and it will build your module, create a zip in the module source directory and launch it on device or emulator.

How to use the build zip in Titanium App:

1: Launch Titanium.
2: Go to Help section.
3: Install titanium Module
4: Browse your module zip file path and choose project in which you want to install.
5: Click ok and done, you are ready to use the module in your app.js.

Note: Installing module in SDK Level is not required until module is very generic and will be used in most of the projects.

For Exposing More APIs in your module rather than just simple build, you can now open CalcModule.java file and start adding methods and properties.

Remember to expose methods and properties with proper annotation:

1: @Kroll.module(name="Calc", id="nigam.ashish.calc") //for module class
2: @Kroll.method
3: @Kroll.getProperty
4: @Kroll.setProperty
5: @Kroll.proxy(creatableInModule=CalcModule.class) //for any added proxy class.

There are many more but for exposing methods and properties only these are required.
You can check out lifecycle methods and events for proxy and viewProxy on Appcelerator GitHub Page.

Life cycle methods:

Methods Demo:

View proxy for exposing view:

View or creating custom view:

Passing Parameters to methods:

These are basics about view and proxy which can be seen from github.

Adding 3rd party JARs in module: 

Right Click on your project and click on build path--> configure build path --> and on libraries section add external JAR.

Browse the jar and add it to your project. Import the file in your class and start using them for module development.


Feel free to write your comment on this and any question related to android module development.