How to use plugin for phonegap - iphone

I am new in phonegap development . I have created one plugin class for iphone which contains some method for encryption. I want to use that .h and .m file to encrypt my data and get the data from my class file in my html page. But i don't have any idea how to call that class function in my javascript file as a result of my page. Please any one have idea how to call any class file and its method in javascript for iphone application then help me .I am waiting for reply.

See the link that Paul answered. For a quick run down, there are a couple ways to do this, but mine usually end up something like this.
Javascript:
PhoneGap.exec("NameOfObjectiveCFile.nameofMethod","parameter1", "parameter2");
Objective C:
-(void)nameOfMethod:(NSMutableArray*)paramArray withDict: (NSMutableDictionary*) options
{
//Do your stuff
//Access your params you sent in javascript by doing the following
NSString *parameter1 = [paramArray objectAtIndex:0];
//Send stuff back to Javascript using a callback function
NSString *jsCallBack = [NSString stringWithFormat:#"nameofJavascriptFinishedMethod(%#)",parameterToSendBack];
[self.webview stringByEvaluatingJavaScriptFromString:jsCallBack];
}
Back to Javascript:
function nameofJavascriptFinishedMethod(parameterFromObjectiveC)
{
//Do stuff with information from objective C
}
Also remember you need to register your plugin in your Phonegap.plist
Hope this helps, good luck.
Update: If you want your html to send information to your plugin, i'd use an html form or button or trigger an action that will call your javascript function (The first one above) and pass your variables gathered from your fields. See this link for form basics.
Update 2
1)Create new phonegap project in xcode and build to get www folder
2)Add your existing Encryption objective C files to project
3)Create new objective C class, call it EncryptPlugin (See step 5 for next)
4)Edit PhoneGap.plist file
a)add a new entry under Plugins
b)name it EncryptPlugin String EncryptPlugin
5)Header file for EncryptPlugin should look like this
#import <Foundation/Foundation.h>
#import <UIKit/UIkit.h>
#ifdef PHONEGAP_FRAMEWORK
#import <PhoneGap/PGPlugin.h>
#else
#import "PGPlugin.h"
#endif
#interface EncryptPlugin : PGPlugin {
}
-(void) useMyEncryptionFiles:(NSMutableArray*)paramArray withDict:(NSMutableDictionary*)options;
#end
6)Implementation file should look like this
#import "EncryptPlugin.h"
#import "EncryptPacket.h"
#implementation EncryptPlugin
//phonegap magic -- basically ignore
-(PGPlugin*) initWithWebView:(UIWebView*)theWebView
{
self = (PdfCreator*)[super initWithWebView:theWebView];
return self;
}
//The method that your javascript is going to call
-(void) useMyEncryptionFiles:(NSMutableArray*)paramArray withDict:(NSMutableDictionary*)options
{
//This gives you your string
NSString *stringFromJavascript = [paramArray objectAtIndex:0];
EncryptPacket *ep = [[EncryptPacket alloc] init];
NSString *encryptedString = [ep encryptRequest:stringFromJavascript];
NSLog(#"encryptedString = %#",encryptedString);
}
#end
7)In your html javascript call the function using something like this
p1.html
<head><script type="text/javascript" src="encryptdata.js"></script></head>
<body>
<input type="password" name="confirmPassword" id="confirmPassword" value="" />
<input type="button" value="FetchR" onclick="fetchRelation()"/>
</body>
encryptdata.js
function fetchRelation()
{
var getvalue=document.getElementById('confirmPassword').value;
//what is next step....... to send the data to the plugin class
PhoneGap.exec("EncryptPlugin.useMyEncrptionFiles",getValue);
}
This should get you started. If you want to send stuff back to your html javascript then use the function I specified above:
NSString *jsCallBack = [NSStringstringWithFormat:#"nameofJavascriptFinishedMethod(%#)",parameterToSendBack];
[self.webview stringByEvaluatingJavaScriptFromString:jsCallBack];
Hopefully this helps, you should be able to figure it out with these instructions. They probably aren't perfect, but I didn't have time to put it all together and compile it using your code. Good luck.

See How to Create a PhoneGap Plugin for iOS

Related

Build less #import url dynamically

While working on a google webfont import mixin, I noticed that it is not possible to build #import URLs dynamically.
.gFontImport (#name, #weights, #subsets) {
#url: "http://fonts.googleapis.com/css?family=#{name}:#{weights}&subset=#{subsets}";
#import url(#url);
}
Which can be narrowed down to
#url: "http://localhost/test.css";
#import url(#url);
Neither any of these additional tests work:
#import url("#{url}"); // this one renders at least
#import url(~"#{url}");
When the compiler renders the CSS file the #import URL is always left unchanged, e.g. "#{url}"
It seems to work in 1.4 beta.
1.4
Doing something like this (I tried it out at less2css.org) in LESS:
.gFontImport (#name, #weights, #subsets) {
#import url('http://fonts.googleapis.com/css?family=#{name}:#{weights}&subset=#{subsets}');
}
.gFontImport("Roboto+Slab",400,latin);
will have the expected output in CSS:
#import url('http://fonts.googleapis.com/css?family=Roboto+Slab:400&subset=latin');
<=1.3.3
If it does not work for you, you can use a workaround that injects the #import call into a selector name:
.gFontImport (#name, #weights, #subsets) {
#gimport: ~"#import url('http://fonts.googleapis.com/css?family=#{name}:#{weights}&subset=#{subsets}');";
#{gimport} some-selector {/* */};
}
so calling something like this in LESS:
.gFontImport("Roboto+Slab",400,latin);
will output this in CSS:
#import url('http://fonts.googleapis.com/css?family=Roboto+Slab:400&subset=latin');
some-selector {
/**/
}
This works, but it is a tiny bit messy. In a javascript implementation of LESS you can use
`'\n'`
and
`'\t'`
in the string interpolation to make it look a bit tidier.
I've made a gist with working mixins for both versions
https://gist.github.com/line-o/5568723
A working example, that defines font sets :
(with Less v1.7.3)
// Google font import mixin
.gFontImport (#name; #weights: 400; #subsets: latin) {
#nameEsc: ~`"#{name}".replace(/'([^']+)'/,'$1').replace(' ', '+')`;
#import url('http://fonts.googleapis.com/css?family=#{nameEsc}:#{weights}&subset=#{subsets}');
}
// Font sets
// The variable #post-fontset is dynamic (user input)
// ------------------
// foo1
.font(#fontset) when (#fontset = foo1){
.gFontImport('Roboto');
.gFontImport('Lato');
}
.font-text() when (#post-fontset = foo1){
font-family:Lato;
}
.font-headings() when (#post-fontset = foo1){
font-family:Lato;
}
.font-sitetitle() when (#post-fontset = foo1){
font-family:Roboto;
}
// foo2
.font(#fontset) when (#fontset = foo2){
.gFontImport('Oswald');
.gFontImport('Lato');
.gFontImport('Roboto Slab');
}
.font-text() when (#post-fontset = foo2){
font-family:'Roboto Slab';
}
.font-headings() when (#post-fontset = foo2){
font-family:Lato;
}
.font-sitetitle() when (#post-fontset = foo2){
font-family:Oswald;
}
// Using the mixins in the CSS
// ------------------
// This executes the font import mixin
.font(#post-fontset);
// Site title
h1{.font-sitetitle();}
// Heading
h2, h3, h4, h5, h6{.font-headings();}
// Text
body{.font-text();}

iPhone unit testing for viewController

I have a controller class in which i want to write the test case for the code which executed on the button click .In my testClass.m file i have following code from which i want to call the button from testClass.m . will this code work??
-(void)testcheckTheArrayForNull
{
viewController.temp=#"c";
viewController.buttonCount=1;
[viewController goButton:self];
STAssertNotNil(viewController.setUpArray,#"set up Array is not nil");
}
By this code will my control transfer to goButton???
I would say this could work, but you didn't provide code for goButton, setUpArray and I have no idea what temp or buttonCount do - so just guessing.

How to make "SBAwayController * controller = [objc_getClass("SBAwayController") sharedAwayController]" working?

I want to check whether the screen is locked with private api.
And I get some code from google:
#import <SpringBoard/SpringBoard.h>
#import <SpringBoard/SBAwayController.h>
Class clsAway = objc_allocateClassPair(clsAlert, "SBAwayController", 0);
objc_registerClassPair(clsAway);
Class clsAwayController = objc_getClass("SBAwayController");
SBAwayController * controller = [clsAwayController sharedAwayController];
if ([controller isLocked]){
NSLog(#"double check Home ,now YES Lock");
}
else{
NSLog(#"double check Home ,now NO Lock");
}
To make these code to work, I download the private headers from kennytm's github and import SpringBoard.h and SBAwayController.h
Compile ok and run it on my iPhone 4S, it seems that I can get a non-nil pointer with objc_getClass("SBAwayController");
But the program crashed at line:
SBAwayController * controller = [clsAwayController sharedAwayController];
with an error: '+[SBAwayController sharedAwayController]: unrecognized selector sent to class 0x1456c0'
Any other works do I need to make these code to work?
I know that the usage of private api can cause the rejection from Apple, but I just want to know how to make it work. Thanks for any suggestions!
SBAwayController WAS NOT REMOVED IN iOS 5. How can you expect to use a SpringBoard method from another process? SpringBoard is NOT a framework. It's an executable.
I believe SBAwayController was removed in the iOS 5. I checked SpringBoard and it has only reminiscences of this class.
Victor is wrong. The class is still present in iOS 6
cy# c = SBAwayController.sharedAwayController;
#"<SBAwayController: 0x1c510580> <SBActivationContext: 0x1c50be50> activate: deactivate: "
cy# printMethods(SBAwayController);
[{selector:#selector(hasEverBeenLocked),implementation:0x109c49},{selector:#selector(activateLostModeForRemoteLock:),implementation:0x116505},{selector:#selector(unlockWithSound:),implementation:0x110835},{selector:#selector(frontLocked:animate:automatically:),implementation:0x1120d5},{selector:#selector(cancelDimTimer),implementation:0x11291d},{selector:#selector(activeAwayPluginController),implementation:0x116885},{selector:#selector(shouldShowInCallUI),implementation:0x116111
...

Webkit communication with native environment

If I have a webkit view loaded in my Android or iPhone app, can I pass data back and forth from the page in webkit?
For example, can I pull an html view down from the web and populate a form in that view with data stored on my device?
Yes in Android using addJavaScriptInterface().
class MyInterface {
private String someData;
public String getData() { return someData; }
}
webview.addJavaScriptInterface(new MyInterface(), "myInterface");
And in the html in your webview.
<script type="text/javascript">
var someData = myInterface.getData();
</script>
By the way, if the webpage you are using is not yours (so that you can't modify it), you can insert javascript inline. For instance:
webview.loadUrl("javascript:document.getElementById('someTextField').value = myInterface.getData();");
For iPhone you can call a JavaScript function from Objective-C by using stringByEvaluatingJavaScriptFromString.
For instance, to get the value of an input field named "fname":
NSString * fString =[webView stringByEvaluatingJavaScriptFromString:#"document.getElementByName(\"fname\").value"];
NSLog(#"fString: %#",fString);

How to call Objective-C from Javascript?

I have a WebView, and I want to call a view in Objective-C from JavaScript. Does someone know how I can do this?
I have this code in my ViewController:
- (BOOL)webView:(UIWebView *)webView2
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType {
NSString *requestString = [[request URL] absoluteString];
NSArray *components = [requestString componentsSeparatedByString:#":"];
if ([components count] > 1 &&
[(NSString *)[components objectAtIndex:0] isEqualToString:#"myapp"]) {
if([(NSString *)[components objectAtIndex:1] isEqualToString:#"myfunction"])
{
NSLog([components objectAtIndex:2]); [[Airship shared] displayStoreFront]; //<- This is the code to open the Store
NSLog([components objectAtIndex:3]); // param2
// Call your method in Objective-C method using the above...
}
return NO;
}
return YES; // Return YES to make sure regular navigation works as expected.
}
And in Javascript:
function store(event)
{
document.location = "myapp:" + "myfunction:" + param1 + ":" + param2;
}
But nothing happens.
The standard workaround for UIWebView is to set a UIWebViewDelegate, and implement the method webView:shouldStartLoadWithRequest:navigationType:. In your JavaScript code, navigate to some fake URL that encodes the information you want to pass to your app, like, say:
window.location = "fake://myApp/something_happened:param1:param2:param3";
In your delegate method, look for these fake URLs, extract the information you need, take whatever action is appropriate, and return NO to cancel the navigation. It's probably best if you defer any lengthy processing using some flavor of performSelector.
The window.location method of calling objective c from JS isn't recommended. One example of problems: if you make two immediate consecutive calls one is ignored (since you can't change location too quickly) - try it yourself..
I recommend the following alternative approach:
function execute(url)
{
var iframe = document.createElement("IFRAME");
iframe.setAttribute("src", url);
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
iframe = null;
}
You call the execute function repeatedly and since each call executes in its own iframe, they should not be ignored when called quickly.
Credits to this guy.
Obliviux,
Your code seems to be perfect.
The reason for the problem is that you must have missed to map the delegate.
Either
Connect the delegate of the webView to the file owner in the .xib file
or
Use webView.delegate = self;
in your viewDidLoad.
Thanks
Like people said here, you have to use the method webView:shouldStartLoadWithRequest:navigationType: from the UIWebviewDelegate.
This api http://code.google.com/p/jsbridge-to-cocoa/ does it for you. It is very lightweight. You can pass images, strings and arrays from javascript to objective-C.
I had an issue with this approach: I wanted to send several messages to the iphone device, but it seemed that they were "overlaped" as they could not process all of them sequentially.
Example: when executing this code:
window.location = "app://action/foo";
window.location = "app://action/bar";
The action foo was never executed.
What I had to do was the following:
waitingForMessage = false;
function MsgProcessed(){
waitingForMessage = false;
}
function SyncLaunchURL(url){
if (waitingForMessage){
setTimeout(function(){SyncLaunchURL(url)},100);
}else{
window.location = url
waitingForMessage = true;
}
}
SyncLaunchURL("app://action/foo");
SyncLaunchURL("app://action/bar");
With this approach, the iphone has to call MsgProcessed() after processing the call. This way works for me, and maybe helps someone with the same problem!
Assuming you're doing an app, you can look at how PhoneGap implements that (or even use it). It's a library that supports back-and-forth communication between JS and OBJ-C. There are other libraries and solutions, as well.
If you're talking about a web app (something the user gets to from Mobile Safari), you can't get to Objective-C from there.
Check this one - understanding XMLHttpRequest responses using this (or other javascript) functions?, it's using objective C to call ajax js function, and get the response after it's done, you know the trick is that webview will be triggered when you change the location in javascript, so you can check the location to know its your javascript call or the real request.
Although this is a very old question now, it keeps getting returned by Google and there is a good answer now: the WebScripting informal protocol. It allows you to expose an objective C object to Javascript.
http://developer.apple.com/library/safari/documentation/appleapplications/Conceptual/SafariJSProgTopics/Tasks/ObjCFromJavaScript.html#//apple_ref/doc/uid/30001215-BBCBFJCD