Showing posts with label Phonegap. Show all posts
Showing posts with label Phonegap. Show all posts

Friday, December 16, 2016

FilePicker Cordova iOS Plugin - Get Files From Photos

Hello,

Recently in one of my iOS project we have requirement to let user browse and select files. So we needed FilePicker plugin for iOS. It should also allow user to browse through document providers like iCloud drive, Dropbox or Google drive.


So after searching for the plugin I found following plugin which works fine for iCloud drive.


https://github.com/jcesarmobile/FilePicker-Phonegap-iOS-Plugin


I would like to thank developer of above plugin as I just added more code to it to fulfill my requirement.

But my other requirements were not fulfilled to pick up photos and videos from saved photos album so I made some changes in this plugin. Here in this blog I will explain how to do this.

First of all install above plugin through command line and open your project in Xcode and open file

Plugins ==> FilePicker.h and Plugins ==> FilePicker.m

This plugin shows pop over menu with all available document providers so first we have to add option to browse photos and videos.

Open FilePicker.h file and add following import statement.

#import

And add following delegates.

@interface FilePicker : CDVPlugin

Now Open FilePicker.m file and find displayDocumentPicker and add following code to it.

[importMenu addOptionWithTitle:@"Photos & Videos" image:nil order:UIDocumentMenuOrderFirst handler:^{
        
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
imagePickerController.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:imagePickerController.sourceType];
imagePickerController.allowsEditing = NO;
imagePickerController.videoQuality = UIImagePickerControllerQualityTypeHigh;
imagePickerController.delegate = self;
[self.viewController presentViewController:imagePickerController animated:YES completion:nil];

}];


This will add menu and we set delegate to self so now we have to callback functions. Add following function in the file.

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
    if ([mediaType isEqualToString:@"public.image"]){
        NSData *imageData = UIImagePNGRepresentation((UIImage*) [info objectForKey:UIImagePickerControllerOriginalImage]);
        NSString* size = [NSString stringWithFormat:@"%li",  (unsigned long)[imageData length]];
        NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
        NSNumber *timeStampObj = [NSNumber numberWithInteger:timeStamp];
        NSString* fileName = [timeStampObj stringValue];
        
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        NSString *imagePath =[documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png",fileName]];
        if (![imageData writeToFile:imagePath atomically:NO])
        {
            //send failure response;
            self.pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Failed to cache image data to disk"];
            [self.pluginResult setKeepCallbackAsBool:NO];
            [self.commandDelegate sendPluginResult:self.pluginResult callbackId:self.command.callbackId];
        }
        else
        {
            NSArray *arr = @[
                             @{@"path": imagePath, @"size": size}
                             ];
            
            self.pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:arr];
            [self.pluginResult setKeepCallbackAsBool:NO];
            [self.commandDelegate sendPluginResult:self.pluginResult callbackId:self.command.callbackId];
        }
    }
    else if ([mediaType isEqualToString:@"public.movie"]){
        NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
        NSString* path = [[videoURL absoluteString] substringFromIndex:7];
        NSData *data = [NSData dataWithContentsOfURL:videoURL];
        NSString* size = [NSString stringWithFormat:@"%li",  (unsigned long)[data length]];
        NSArray *arr = @[
                         @{@"path": path, @"size": size}
                         ];
        
        self.pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:arr];
        [self.pluginResult setKeepCallbackAsBool:NO];
        [self.commandDelegate sendPluginResult:self.pluginResult callbackId:self.command.callbackId];
    }
    [picker dismissViewControllerAnimated:YES completion:NULL];
}

So as you can see in above code we are checking if picked media is image, then first we have to move application temp storage as iOS does not allow you to access assets directly from photos so we are making a copy with following code.

NSData *imageData = UIImagePNGRepresentation((UIImage*) [info objectForKey:UIImagePickerControllerOriginalImage]);
NSString* size = [NSString stringWithFormat:@"%li",  (unsigned long)[imageData length]];
NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
NSNumber *timeStampObj = [NSNumber numberWithInteger:timeStamp];
NSString* fileName = [timeStampObj stringValue];

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *imagePath =[documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png",fileName]];
if (![imageData writeToFile:imagePath atomically:NO])
{
}
else
{
}


And for the videos we are sharing absolute URL to result callback. Also the plugin result is now array with path and size attribute. So we have to change the code of plugin to send same result for other document providers. Find out following function in FilePicker.m file.

- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url

And replace it with following function.

- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url {
    
    [url startAccessingSecurityScopedResource];
    __block NSData *pdfData = nil;
    
    NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] init];
    __block NSError *error;
    [coordinator coordinateReadingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL) {
        pdfData = [NSData dataWithContentsOfURL:newURL];
        NSString* size = [NSString stringWithFormat:@"%li",  (unsigned long)[pdfData length]];
        NSArray *arr = @[
                         @{@"path": [url path], @"size": size}
                         ];
        
        self.pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:arr];
        [self.pluginResult setKeepCallbackAsBool:NO];
        [self.commandDelegate sendPluginResult:self.pluginResult callbackId:self.command.callbackId];
    }];
    [url stopAccessingSecurityScopedResource];
    
}

So in JavaScript, following code should work.

FilePicker.pickFile(function(obj) {
alert(obj[0].path);
alert(obj[0].size);
}

Hope this helps you.

Thursday, August 27, 2015

Android Cordova 4.0.2 Webview Intercept Requests

Recently I was working on Android cordova app where I was using cordova 4.0.2 version. In this project I have to intercept urls loaded in webview and do some stuff.

In earlier cordova version we can do following.

myWebView.setWebViewClient(new WebViewClient() {
         public boolean shouldOverrideUrlLoading(WebView view, String url)  {
         }
});

But in newer version of cordova this will not work. So what to do? Here is this blog I am going to explain it.

First of all lets get webView


myWebView = (WebView) this.appView.getView();

Then add WebViewClient to webView.

myWebView.setWebViewClient(new SystemWebViewClient((SystemWebViewEngine) this.appView.getEngine()){
          public boolean shouldOverrideUrlLoading(WebView view, String url) {
          }
          public void onPageFinished(WebView view, String url) {
                   super.onPageFinished(view, url);
          }
});

As you can see in cordova newer version they have added new class SystemWebViewClient in cordova lib that we have to use for accessing functions like shouldOverrideUrlLoading and onPageFinished.

Hope this helps you. 

Wednesday, April 22, 2015

JavaScript identify Android WebView

Hello,

Recently I was working on the cordova project where we have mobile web application hosted on server. With the same URL loaded in Android webview we created native app. Now we have some functionalities in app that should only be available if URL is loaded in Android WebView like camera capture. For that we have to identify webview with JavaScript. In this blog I will explain how to do this.

I added very simple logic. I set custom user agent for WebView from Native android app and just checked that in JavaScript and set global variable. Here is how you can do that.

First of all open res/values/string.xml and add following line.


<string name="user_agent_suffix">AppName/1.0</string>

Then we this Custom Agent from onCreate function of Android Activity.

this.appView.getSettings().setUserAgentString(
            this.appView.getSettings().getUserAgentString() 
            + " "
            + getString(R.string.user_agent_suffix)
         );

So we are setting custom user agent in Android WebView. Now in our app we just have to check this with UserAgent.

Var isNativeApp  = /AppName\/[0-9\.]+$/.test(navigator.userAgent) ? true : false//For checking native app.

That's it now you can check isNativeApp variable anywhere in app to set functions on if the app is running in Android WebView.


Monday, May 12, 2014

iOS 7 Phonegap Change Background Color of Status Bar

Hello,

Recently I was working on Sencha Touch, Phonegap application where we have a requirement to change background color of top status bar of iPhone where we have carrier, wifi and battery symbols. There are two ways to do it. In this blog I will explain both the steps.

First Step

In iOS 7 if you have status bar visible your UI will overlap the status bar and we will take advantage of it. First select your project and go to Deployment info. Make sure you have Hide during application launch checkbox and set status bar style as default.

Now your webview will overlap the UI and the status bar will be transparent. So we can add a component on top of our page with height 20 pixel and preferred background color so your status bar will have same background color. For example I added docked panel in Sencha Touch with fixed height and background color in my main container. 

Ext.define('MyApp.view.LaunchView', {
    extend : 'Ext.Panel',
    xtype : 'launchmain',

    config : {
        layout : 'card',
        
           items : [{
                    xtype: 'panel',
                    docked: 'top',
                    style: {
                        'background-color': '#34495E',
                        'color':'#ffffff'
                    },
                    height: 20
                    
           }]
    }
});

Since this is may main container all the views added in this container will have this panel and top. Now issue could be if you have some external pages loaded in app on which you don't have control then this panel will not be there you can not have top component with background color. For that follow step 2

Second Step

Here in this step we will add component on top of our webview in our main iOS 7 view. Hence it will be available throughout the app. For that add following code in didFinishLaunchingWithOptions method of AppDelegate.m

 if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
        UIView *topView = [[UIView alloc] init];
CGRect screenRect = [[UIScreen mainScreen] bounds];
        topView.frame = CGRectMake(0, 0, screenRect.size.width, 20);
        topView.backgroundColor = [UIColor colorWithRed:52/255. green:73/255. blue:94/255. alpha:1];
        [self.window.rootViewController.view addSubview: topView];
    }

Here we are added another view with required background color on top of webview. Now we have to shift down webview for 20 pixel so that this view would be visible. For that add following code to viewDidLoad function of your MainViewController.m file. 

if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
        CGRect viewBounds = [self.webView bounds];
        viewBounds.origin.y = 20;
        viewBounds.size.height = viewBounds.size.height - 20;
        self.webView.frame = viewBounds;
    }

As you can see in above code we are changing the origin of webview and shift it 20 pixel down. You can simply add above code to avoid overlapping of UI.


Monday, April 21, 2014

Cordova build JAR File From Source Code (For MAC OSX only)

As we know that now Cordova only support command line interface. Earlier with download you get cordova.jar file, that you can directly import to eclipse project and create android cordova file. Now with new download you only get source code, you have to manually generate cordova.jar file and import to eclipse. In this blog I will explain you the steps. First download Cordova source code from the Download.

Extract the content on the desktop. Now you will need following two things.

Apache Ant 1.8.0 or greater
Android SDK which you can download from Android Developer Portal

Download and extract SDK to desktop. Now we will install apache ant. Open the terminal and run following command.

ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"

After homebrew is installed we will install ant.

brew install ant

Now ant is installed, we will configure modify paths in bash profile file for android SDK. Run following command in terminal

nano ~/.bash_profile

Go to and of the file and paste following code.


export PATH=/Users/yourusername/Desktop/adtdirectotyname/sdk/tools:$PATH

Click Control+X, Y, Enter. It will save your new file. Now go to your Cordova source code and go to cordova-android/framework and run following command.

android update project -p . -t android-19
ant jar

And it will generate cordova .jar file in the framework folder, you can use that file in your eclipse.

Thursday, January 2, 2014

Cordova Android Application in Play Store, Does Not Support Tablet

Hello,

Wish you all a very Happy New Year, This is my first blog of 2014.

Recently we faced a strange issue with our Corodva Application. We built Sencha Touch application and used Cordova as native wrapper. When we uploaded APK to Google Play store, there was a notification that, application does not support tablets.

We were not sure what could be the issue, as we did not specify anything like this in application. First we thought it's a issue related to layouts, as some tablets may have high definition resolution. So we added all the layout files like ldpi, mdpi, hdpi and xhdpi. But still issue was the same. Later on we figured out that, this issue was actually related to permissions mentioned in Android manifest file. Normally when we create phoengap application for android, we specify following permissions.

<supports-screens android:largeScreens="true" android:normalScreens="true" android:smallScreens="true" android:resizeable="true" android:anyDensity="true" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />

If you see the above permission, we specified permission like RECEIVE_SMS, WRITE_EXTERNAL_STORAGE, RECORD_AUDIO etc. IT may be possible that the tablet only allows Wifi connection and it does not have any sim card or external storage so it may not receive the SMS or record audio or write to external storage. But we requested the permission in manifest file and which was not possible to grant so the application can not work on tablets.

If you face the same issue try and remove the permissions which are not necessary and may not be available in some tablets. After removing permissions, upload APK to Play store and it will work.

Hope this helps you.

Monday, May 13, 2013

Passing Query String With Index.html file in iOS Phonegap (Cordova)

Hello,

Imagine a scenario that you have Sencha Touch/ jQuery mobile application and you have used Phonegap (Cordova) to compile it to native iOS application.  Now your application expects some params like authentication token, or user id or anything it can be. You need to send this params along with your index.html file so that you can use it in app launch function. Have you ever faced this situation. If yes then here is the solution. Please remember this solution is specifically for iOS Cordova application.

First let's see how normally it works. When you create a Cordova based application in XCode, You have AppDelegate.h and AppDelegate.m file. Open AppDelegate.m file and find a function below.


- (BOOL) application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions

In this function find the following lines of code.

self.viewController.wwwFolderName = @"www";
self.viewController.startPage = @"index.html";

This specify that web assets folder is WWW and start page is index.html. If you have some other start page you can change the name here. Now if you try to pass query string as follow, it will not work.


self.viewController.startPage = @"index.html?query1=value1";

Because it treats it as page name and there is no such page. So how to resolve this.

First of all remove the start page name from code.

self.viewController.startPage = @"";

Now we will implement NSURL interface and add some custom functions in it to handle the query string. Add following code to your AppDelegate.m file above implementation of AppDelegate

@implementation NSURL (Additions)

- (NSURL *)URLByAppendingQueryString:(NSString *)queryString {
    if (![queryString length]) {
        return self;
    }
    
    NSString *URLString = [[NSString alloc] initWithFormat:@"%@%@%@", [self absoluteString],
                           [self query] ? @"&" : @"?", queryString];
    NSURL *theURL = [NSURL URLWithString:URLString];
    [URLString release];
    return theURL;
}

@end

This function accepts query string and add it to URL and create new URL. Now add following code at end of didFinishLaunchingWithOptions function.

NSString* newQueryString = @"query1=value1&query2=value2&query3=value3";
NSURL *newurl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"index" ofType:@"html" inDirectory:@"www"]];

newurl = [newurl URLByAppendingQueryString:newQueryString];
[self.viewController.webView loadRequest:[NSURLRequest requestWithURL:newurl]];


Above code will build custom URL with query string and load the URL in iOS webview.

Hope this helps you.




Thursday, February 28, 2013

iOS Phonegap ( Cordova ) Open Link in Safari


Have you ever encountered the situation in your corodova project where you have set OpenAllWhitelistURLsInWebView to YES in your Cordova.plist file and you have to open one single URL in external Safari application.? If yes than read this blog.


For cordova we have to whitelist some external urls if we have any. By default it will open in external Safari browser to prevent that we have to set following in Cordova.plist file.

This will open all the external urls in same web view. So to add exception URL which should open in external Safari browser make following changes to AppDelegate.m file. 

- (BOOL) webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *url = [request URL];
    NSString* urlString =  [url absoluteString];
    
    if ([urlString rangeOfString:@"www.myexternalurl.com"].location == NSNotFound) {

    }
    else {
        [[UIApplication sharedApplication] openURL:[request URL]];
        return NO;
    }
}


and in your JavaScript simply write following line.

window.location.href = "www.myexternalurl.com";

Once web view start loading the url it will invoke shouldStartLoadWithRequest event. Here we are checking the url string and if we find it to be external URL, it will be opened in external Safari browser. Webview will not load this URL since we return NO.

Sunday, February 10, 2013

Sencha Touch, Phonegap (Cordova) application not working in Android 4.x - Here is the Solution

Have you ever encountered this issue? When you try to deploy your Cordova+ Sencha Touch app in Android 4.1, your app is not working. It just shows the white screen. In this blog I will explain the issue and mention solution for it.

What is the Issue?

It's not issue of sencha touch but it's an issue of Android. It's not possible to load any URL in android webview which have certain parameters. This issue is reported since Android 3.0 but still it's not resolved. We know that when we use cordova it uses file protocol to open any files. We load index.html file using following URL.

file:///android_assets/www/index.html 
Now we know that Sencha Touch uses Ext.Loader to load the controllers, stores and model files. When Loader tries to load files, URL would be formed as follow.

file:///android_assets/www/app/controller/MyController.js?_dc=xxxxxxxx

That's why it's break because it adds _dc param in each load request of file. What is this _dc param? This is cache buster param that is added by default by Ext framework. Most of the browsers caches the request and particularly GET request. So Ext framework always add _dc param which has unique datetime stamp. So URL looks always different hence browser does not return cached result. And that's what breaks the app in Android.

What is the Solution?

One solution is to minify all your secha touch classes with Sencha Touch build commands. You have to install Sencha SDK tools and setup necessary environment variables for it. After that go to directory of your application.

cd ~/path/to/my/app

After this create jsb3 file for your application using following command

sencha create jsb -a index.html -p app.jsb3

After this build your application.

sencha build -p app.jsb3 -d ./

This final command takes all of the files listed in the jsb and combines them into a single file, which it then minifies to make as small as possible. The output is a file called all-classes.js, which contains all of the framework classes plus your application classes.

You can reference this file to index.html file so you have minified version of your application and it's ready for the production.


Other solution is to disable caching but that is not recommended. You can disable caching for Ext.Loader as follow.

Ext.Loader.setConfig({ disableCaching: false });

Also you can disable caching for all the Ajax request.

Ext.Ajax.setDisableCaching(false);

This will remove _dc param from your ajax request also Ext.Loader will not add _dc param in file download request.

Hope this helps you.


Tuesday, September 25, 2012

Cordova (Phonegap) 2.0 In Android 4.1 Jelly Bean XMLHttpRequest Could not Load Error

Hello,

This is short and quick blog on cordova and android Jalley Bean issue. Have you ever encountered error "XMLHttpRequest Could not Load" while working with Android 4.1 Jalley Bean? Complete error is XMLHttpRequest Could not Load, origin null is not supported.

First when I get this error, I thought it's a cross domain issue, but it's not. When you are using cordova all your JavaScripts are loaded by file:/// protocol. So it really does not matter if we use Ajax or JsonP request. Because there is nothing like domain here. So what really is the issue?

While debugging for this error I noticed in my chrome developer tools that, it's trying to fire an XMLHttpRequest on my local machine and that XMLHttpRequest was initiated by some cordova functions. and that was using localhost url which does not exists. So it was breaking the whole app.

How to get rid of this? While debugging I found that this XMLHttpRequest was initiated by polling function of cordova. Cordova has polling mechanism to get response from native API calls. In my app, there wasn't any native API call so I disabled the polling. Find the following line in your cordova file.

UsePolling:true,

and set it to false as follow.

UsePolling:false,

That's it and there will not error on XMLHttpRequest.

Hope this helps you.

Saturday, March 17, 2012

Get device token for apple push notifications in sencha touch and phone gap

Hello,

Recently I was working on Apple push notifications with sencha touch and phonegap project. Requirement was to get device token in JavaScript file so that it can be sent to server for getting push notifications. For that first thing we need to do is register device to get Push notifications.

Please make sure that you have real apple device like iPad, iPhone or iPod touch to test this. This will not work in Simulator.

To register device for push notifications add following in your AppDelegate.m file.  Find method


- (BOOL) application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions

Also add following line to define token variable.


@synthesize token;


and add following code at end of the method.


NSLog(@"Registering for push notifications...");    
    [[UIApplication sharedApplication] 
     registerForRemoteNotificationTypes:
     (UIRemoteNotificationTypeAlert | 
      UIRemoteNotificationTypeBadge | 
      UIRemoteNotificationTypeSound)];

This will register device for getting push notifications. Please make sure that you have added provisioning profile which configured with non wild card app id and app is configured to receive  push notifications in your development portal. Also you need valid developer certificate.

After that you need to add following methods at end of the file.

- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { 

    
    self.token = [[[[deviceToken description]
                    stringByReplacingOccurrencesOfString: @"<" withString: @""]
                   stringByReplacingOccurrencesOfString: @">" withString: @""]
                  stringByReplacingOccurrencesOfString: @" " withString: @""];
    
    NSLog(@"My token is: %@", self.token);
}

- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err { 
    
    NSString *str = [NSString stringWithFormat: @"Error: %@", err];
    NSLog(str);    
    
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    
    for (id key in userInfo) {
        NSLog(@"key: %@, value: %@", key, [userInfo objectForKey:key]);
    }    
    
}


This will get device token and store it to token. Now to send this token to JavaScript we will create a phonegap plugin. Please make sure that this code will work with Phonegap version 1.5.0. They named this version as Cardova.

First create folder inside plugins folder of your project folder and name it as PushToken and add two files to it PushToken.m and PushToken.h

Open PushToken.h file and add following code to it.



#import <Foundation/Foundation.h>
#import <Cordova/CDVPlugin.h>

@interface PushToken : CDVPlugin{
    
    NSString* callbackID;  
}

@property (nonatomic, copy) NSString* callbackID;

- (void) getToken:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;

@end



Now open PushToken.m file and add following code to it.

#import "PushToken.h"
#import "AppDelegate.h"

@implementation PushToken

@synthesize callbackID;

-(void)getToken:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options  {
    self.callbackID = [arguments pop];
    
    NSString *token = ((AppDelegate *)[[UIApplication sharedApplication] delegate]).token;
    
    CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[token stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    
    if(token.length != 0)
    {
        [self writeJavascript: [pluginResult toSuccessCallbackString:self.callbackID]];
    }else {    
        [self writeJavascript: [pluginResult toErrorCallbackString:self.callbackID]];
    }
}

@end

Now we have to map this plugin. For that open Cordova.plist file and following key value pair to it.

PushToken : PushToken

After that open AppDelegate.h file and add following line to it.

@property (retain, nonatomic) NSString* token;

That's it of phonegap side now we have to create JavaScript file form where we will execute this plugin code. Create JavaScript file with name PushToken.js and add it to www folder. Add following code to it.

var PushToken = {
    getToken: function(types, success, fail) {
        return Cordova.exec(success, fail, "PushToken", "getToken", types);
    }
};

Add link of this JavaScript file to your index.html page after phonegap JavaScript file. To get device token wherever you want use following code.


PushToken.getToken(     
                     ["getToken"] ,           
                     function(token) {
                              global.token = token; 
                     },
                     function(error) {
                              console.log("Error : \r\n"+error);      
                     }
          );

That's it and you have your device token.




Wednesday, March 7, 2012

Whitelist rejection error in Xcode for Sencha touch 2 and Phonegap

Hello,

If you have developed iPhone application using sencha touch 2 and phonegap and if your application is using Ajax request or JsonP request you might have above error. That's not the issue of cross domain because when you convert your sencha touch application to native app using phonegap, it loads index.html and other js files in browsers using file uris. Something like below

file://..
So there is no issue of cross domain. But still if you get above error. That's because of  iPhone security restriction. You must add your domain to whitelist. For that open the file phonegap.plist and you should see following.


See the external host. Here you have to add your domain something like below

TEST.MYDOAMIN.COM
Make sure that you don't add http or other protocols. Just a domain name and it should work.