passing value from iOS native code to cordova - ios

I have some values generated from my native code that I would like to pass to phonegap. These data are generated in real time and are not directly influenced by the user's actions through the phonegap gui.My native code is part of a plugin that I made.
What is the best way to approach this? I want to have a function to send data over anytime and have a listener on the cordova side. I'm using Cordova 1.5 with Xcode 4.3.
Here is what I have so far:
swipe.js:
var swipe={
callNativeFunction: function (success, fail, resultType) {
return Cordova.exec( success, fail,
"ca.swipe",
"nativeFunction",
[resultType]); }
};
index.html:
...
function callNativePlugin( returnSuccess ) {
swipe.callNativeFunction( nativePluginResultHandler, nativePluginErrorHandler, returnSuccess );
}
function nativePluginResultHandler (result) {
alert("SUCCESS: \r\n"+result );
}
function nativePluginErrorHandler (error) {
alert("ERROR: \r\n"+error );
} ... <body onload="onBodyLoad()"> <h1>Hey, it's Cordova!</h1>
<button onclick="callNativePlugin('success');">Success</button>
<button onclick="callNativePlugin('error');">Fail</button>
</body> ...
swipe.h:
...
#interface swipe : CDVPlugin
- (void) nativeFunction:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
#end
swipe.m:
...
- (void) nativeFunction:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options {
NSLog(#"Hello, this is a native function called from PhoneGap/Cordova!");
//get the callback id
NSString *callbackId = [arguments pop];
NSString *resultType = [arguments objectAtIndex:0];
NSMutableArray *GlobalArg=arguments;
CDVPluginResult *result;
if ( [resultType isEqualToString:#"success"] ) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: #"Success :)"];
//writes back the smiley face to phone gap.
[self writeJavascript:[result toSuccessCallbackString:callbackId]];
}
...
The code that I have right now has nothing for doing what I want. I'm not really sure how to setup the code in both cordova and native.

Sounds like you need to be able to talk back down to PhoneGap from objective C, in which case you should be able to use something like:
NSString *jsResult = [theWebView stringByEvaluatingJavaScriptFromString:#"hello()"];
NSLog(#"jsResult=%#",jsResult);
And if you have a JS function like "hello" in your index.html like this:
function hello(){return "hello";}
Its a way of talking back to your PhoneGap web layer

create a class of type CDVPlugin
import #import in that class
initialize a handler method .h class
- (void)Device:(CDVInvokedUrlCommand *)command;
and implement the method in .m class
- (void)openDevice:(CDVInvokedUrlCommand *)command{
CDVPluginResult *pluginResult = nil;
BOOL checkOpenDevice=NO;
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:checkOpenDevice];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}
}
in this way through self.commandDelegate your data will be able to reach to the cordova class
if the .js file hit(calls) that particular method which is initialized in .h class.

Related

Keep listener for iOS Cordova plugin variable changes

I'm building an iOS Cordova plugin, in this plugin i have a variable that is always changing values.
When i call this plugin method that returns this variable from js, I want it to stay active and always get the new changed value from Objective-c.
This is my code:
/**
*This method will return the Volume of the user's speech ( It can be used as a UI feedback)
*/
- (void) getRecognitionVolume:(CDVInvokedUrlCommand*)command
{
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[NSString stringWithFormat:#"%1.6f", volumeLevel]];
[pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}
js code:
getVolumeBtn.addEventListener('click', function() {
cordova.exec(
function successCallback(data) {
volumeDiv.innerHTML ="Volume: "+ data;
},
function errorCallback(err) {
alert('Error');
},
'VoiceControl',
'getRecognitionVolume',
[]
);
});
So to conclude I want the volumeDiv to always hold the new volume value.
Any help would be appreciated.
The problem was that I didn't fully understand the way setKeepCallback works:
I thought if set to true it will automatically keep the method running and sending the new value whenever the variable changes.
The way I have to use it is whenever the value changes I must send the result again.
Here's where I pass the result now:
(this is the handler that's always called when the volume changes in my code)
- (void) pollVolume
{
[self getRecognitionVolume:volumeCommand];
}

Upload file to Node.js server using Socket.io-stream from iOS

I'm writing a native iOS client to interact with a Node.js server using the Socket.IO-objc wrapper. I'm currently able to send individual events to the server just fine. However, the server is using Socket.IO-stream to handle upload file streams, and I need to make my iOS code interact with it somehow. My socket.io wrapper doesn't seem to have any relevant API for accomplishing this. The receiving server.js code is like:
io.sockets.on('connection', function (socket) {
console.log("connection occurring");
ss(socket).on('uploadFile', function (stream, data, callback) {
//...I can't get a 'stream' to this event for it to work with
});
socket.on('passwordLogin', function (data, callback) {
//...I can cause these kind of events just fine
});
//...other event declarations
}
I typically call events in this manner, and it works fine for 'socket.on' declared events:
[_socket sendEvent:#"passwordLogin"
withData:#{...login info...}
andAcknowledge:aCallbackBlock];
I figure I need to expand Socket.IO-objc, unless there is something I'm missing, with something like:
//TODO: Attempt to expand SocketIO to include streams.
- (void) sendEvent:(NSString *)eventName withStream:(NSStream*) stream withData:(id) data andAcknowledge:(SocketIOCallback) function
{
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObject:eventName forKey:#"name"];
// do not require arguments
if (data != nil) {
[dict setObject:[NSArray arrayWithObject:data] forKey:#"args"];
}
SocketIOPacket *packet = [[SocketIOPacket alloc] initWithType:#"event"];
packet.data = [SocketIOJSONSerialization JSONStringFromObject:dict error:nil];
packet.pId = [self addAcknowledge:function];
//Is this even a valid approach?
packet.stream = stream;//<--NEW BIT
if (function) {
packet.ack = #"data";
}
[self send:packet];
}
I'm pretty lost as to what exactly to do, having never really worked with server communications before. I've followed Apple documentation about the built-in NSStream and CFStream objects, but it doesn't seem to get me any closer to interacting with the server's event. Any help is appreciated, as I'm a bit at my wit's end.

Can i change the server url with sudzc?

I am trying to generate source code from a wsdl file for iOS. I've stumbled upon a couple of tools and so far wsclient++ and sudzc at least seem to work. But I need to send requests to different servers with the same soap interface, depending on the state of the iOS app.
In the source code generated by wsclient I can set the server URL via
MyWebService* ws = [MyWebService service];
// // set base url for entire application
[SoapWebService setGlobalBaseUrl: #"http://domain.com"];
NSError* error = nil;
Result* rs = [ws callMethod: p1 param2:p2 error:&error];
Which would me allow me to do something like
if(condition1) [SoapWebService setGlobalBaseUrl: #"http://betaserver.com"];
if(condition2) [SoapWebService setGlobalBaseUrl: #"http://developserver.com"];
if(condition3) [SoapWebService setGlobalBaseUrl: #"http://liveserver.com"];
Is there a way to archive something similar with the source code generated by sudzc?
As long as the soap is the same response you shouldn't have a problem using your code. There is a file that stores the server address. The code generated by sudzc can be modified to any address. I actually created a dynamic way of hitting servers. I will find the file and code I used to do this.
You can search the project for your domain you used for sudzc.
I'm not in front of a mac right now, but I will update later.
UPDATE:
Ok, so I created a settings tab and allowed the user to input a specific ip address if necessary. It saves the IP address in a dictionary and then this file retrieves it from the dictionary. I left some of my original comments and added some in the code so you can see both ways. If it confuses you let me know and I'll edit again. In my sudzc generated code I modified the file to this:
/*
wsUpdateQOH.m
The implementation classes and methods for the wsUpdateQOH web service.
Generated by SudzC.com
*/
#import "wsUpdateQOH.h"
#import "Soap.h"
#import "Settings.h"
#define URL #"http://%#/webServiceAddress/updateqoh.asmx"
/* Implementation of the service */
#implementation wsUpdateQOH
- (id) init
{
if(self = [super init])
{
// take out hard coded address and add variable to have a dynamic IP #"http://www.site.com/webServiceAddress/updateqoh.asmx"
// here is the dictionary return and format of the url string
NSString *savedValue = [[NSUserDefaults standardUserDefaults] stringForKey:#"serverIP"];
self.serviceUrl = [[NSString alloc] initWithFormat:URL, savedValue];
// uncomment for a hard coded address self.serviceUrl = #"http://%#/webServiceAddress/updateqoh.asmx";
self.namespace = #"http://tempuri.org/webServiceAddress/UpdateQOH";
self.headers = nil;
self.logging = NO;
}
return self;
}
- (id) initWithUsername: (NSString*) username andPassword: (NSString*) password {
if(self = [super initWithUsername:username andPassword:password]) {
}
return self;
}
+ (wsUpdateQOH*) service {
return [wsUpdateQOH serviceWithUsername:nil andPassword:nil];
}
+ (wsUpdateQOH*) serviceWithUsername: (NSString*) username andPassword: (NSString*) password {
return [[[wsUpdateQOH alloc] initWithUsername:username andPassword:password] autorelease];
}
// *** Below here is the soap actions ***

Phonegap plugin on iOS not calling native code

I am trying to implement my first phonegap plugin (version 2.3) on iOS - but the call of the native function seems not to work.
My plugin is based on this introduction:
http://docs.phonegap.com/en/2.3.0/guide_plugin-development_ios_index.md.html#Developing%20a%20Plugin%20on%20iOS
So I added to the plugins-section of config.xml:
<plugin name="Echo" value="Echo" />
my calling javascript:
$(document).ready (function (){
$('#testBtn').submit(function () {
alert("test");
var param = ["a", false];
cordova.exec(
function(winParam) { alert("ok"); },
function(err) { alert("error"); },
"Echo", "echo", param);
return false;
});
}
(the alert in the first row gets called by pushing my testBtn, so the rest should also be executed...)
In my plugins-directory:
Echo.h:
#import <Cordova/CDV.h>
#interface Echo : CDVPlugin
- (void)echo:(CDVInvokedUrlCommand*)command;
#end
Echo.m:
#import "Echo.h"
#implementation Echo
- (void)echo:(CDVInvokedUrlCommand*)command
{
NSLog(#"echo!");
}
#end
The echo-Function in Echo.m never gets called ... can anyone tell me why? I don't get any error messages - just nothing happens...
I was struggling in this step like you. then I Called that javascript function after device getting ready. Problem has solved. Now, Its working fine...

TBXML block iOS

I am trying to load xml data using newTBXMLWithURL method and once success block returns xml, I am trying to dispatch it using delegation so that controller receives NSMutableArray of records but I must be doing something wrong and I get an error in console that says "PROGRAM RECEIVED EXC_BAD_ACCESS" I am not sure where I have gone wrong. Code attached below
#import "XmlParser.h"
#import "TBXML+HTTP.h"
#import "NewsObject.h"
#implementation XmlParser
#synthesize delegate = _delegate;
- (void)GetNewsList
{
TBXMLSuccessBlock s = ^(TBXML *tbxml) {
NSMutableArray *arrayOfNews;
TBXMLElement *root = tbxml.rootXMLElement;
TBXMLElement *newsListElement = [TBXML childElementNamed:#"NewsList" parentElement:root];
TBXMLElement *newsElement = [TBXML childElementNamed:#"News" parentElement:newsListElement];
while(newsElement !=nil){
NewsObject *news = [[NewsObject alloc]init];
news.headLine = [TBXML textForElement: newsElement ->firstChild];
news.description = [TBXML textForElement:newsElement ->firstChild->nextSibling];
news.imageUrl = [TBXML textForElement:newsElement->firstChild->nextSibling->nextSibling];
if(arrayOfNews==nil)
arrayOfNews = [NSMutableArray arrayWithObject:news];
else
[arrayOfNews addObject:news];
newsElement = newsElement ->nextSibling;
}
[self.delegate XmlParser:self feedReady:arrayOfNews];
};
TBXMLFailureBlock f = ^(TBXML *tbxml, NSError *error) {
NSLog(#"nay");
};
[TBXML newTBXMLWithURL:[NSURL URLWithString:#"url"]
success: s
failure: f];
}
#end
Input sample:
<xmlData>
<NewsList>
<News newsId="1" providerId="1" articleId="95020" sportId="6" sportName="RBL">
<Headline>Matai signs on with Manly</Headline>
<Description>
Manly has retained another one of its premiership stars with Steve Matai committing to the Sea Eagles until the end of the 2015 season.
</Description>
<Image>
http:google.com/All.png
</Image>
</News>
<News newsId="2" providerId="1" articleId="95019" sportId="7" sportName="RBU">
<Headline>Reds lose Lucas for Brumbies clash</Headline>
<Description>
Queensland has lost key utility back Ben Lucas to injury on the eve of Saturday night's vital match with the Brumbies at Canberra Stadium.
</Description>
<Image>
http:google.com/All.png
</Image>
</News>
</NewsList>
<xmlData>
Thanks for letting us know the actual error message. There is no a single reason for that error or warning.
Also, are you using ARC or just forgot to autorelease the stuff? Which Xcode version and compiler are you using? All these details matter.
I'd say you can fix this avoiding self inside the block:
__block id _self = self;
TBXMLSuccessBlock s = ^(TBXML *tbxml) {
/* use _self inside the block, not self */
};
See https://stackoverflow.com/a/7854315/143097.
Previous answer:
It seems you're calling a method that doesn't exist: newTBXMLWithURL:success:failure:. At least in my version of TBXML it is called: tbxmlWithURL:success:failure:.
I bet there is a hint about this somewhere in the error message, isn't it?

Resources