Archive

Archive for April, 2014

Webworks.js – under the hood on port 8472

April 26, 2014 Leave a comment

Image

A relatively recent change to Webworks apps on BB10, was that you had to include the file:

<script src=”local:///chrome/webworks.js” type=”text/javascript”></script> in order to access the native functionality, such as browser invoke etc. 

Interestingly, if you enable remote web inspector, you can actually see the contents of this file (listed here), and the underlying “gubbins” are exposed.

What webworks.js is actually doing, is that it converts calls such as blackberry.invoke.invoke({target: “sys.browser”,uri: “xxxx”}); to an AJAX call to localhost on port 8472, which does not appear to be accessible from outside the device itself.

The full protocol is unlikely to be published, and it’s not a good idea to use this protocol directly, it’s more for academic interest.

Here is an example AJAX request

  1. Request URL:
  2. Request Method:
    POST
  3. Status Code:

    200 OK
  4. Request Headersview source
    1. Accept-Language:
      en-GB,en;q=0.8
    2. Content-Type:
      application/json
    3. Origin:
      local://
    4. User-Agent:
      Mozilla/5.0 (BB10; Touch) AppleWebKit/537.35+ (KHTML, like Gecko) Version/10.2.1.2141 Mobile Safari/537.35+
  5. Request Payloadview source
     
    {,…}
    1. request“%7B%22target%22%3A%22sys.browser%22%2C%22uri%22%3A%22http%3A%2F%2Fwww.google.com%2Fpatents%2FUSD293241%3Fdq%3DResearch%2Bin%2BMotionw%26source%3Duds%22%7D”
  6. Response Headersview source
    1. Access-Control-Allow-Headers:
      Content-Type
    2. Access-Control-Allow-Origin:
      *, local://

 

 

 

 

 

 

 

Advertisements
Categories: Uncategorized

Send Email from PhantomJS

April 22, 2014 Leave a comment

Image 

I was looking for a way to run automated tests on Javascript, and one of the key requirements of automated tests, are that the results are communicated back. As long as I’m just looking for erroneous / exceptional events then email is a great way to get my attention. But I wanted to find an online service that would provide this for me, rather than writing my own server side code, so I tried a few, and came up with mailgun.net

function ObjToQs(obj)
{
str = ”;
for(key in obj) {
str += key + ‘=’ + obj[key] + ‘&’;
}
str = str.slice(0, str.length – 1);
return str;
}

var page = require(‘webpage’).create(),
url = ‘https://api.mailgun.net/v2/sandboxed7c45b35fc04752931f87faecae4428.mailgun.org/messages&#8217;,
data = {
“from” : “Mailgun Sandbox <postmaster@sandboxed7c45b35fc04752931f87faecae4428.mailgun.org>”,
“to” : “xxxx@gmail.com”,
“subject” : “Hello!”,
“text”: “Test from mailgun / phantomjs”
};

page.customHeaders={‘Authorization’: ‘Basic ‘+btoa(‘api:key-xxxxxx’)};
page.open(url, ‘post’, ObjToQs(data), function (status) {
if (status !== ‘success’) {
console.log(‘FAIL to load the log’);
console.log(status);
} else {
console.log(‘Log success’);

var result = page.evaluate(function () {
return document.body.innerText;
});

console.log(“log Result: ” + result);
phantom.exit();
}
});

 

I’ve left out my API key, you can get your own at mailgun.net – 

A successful result should be as follows:

C:\research\phantomjs>phantomjs errorreport.js
Log success
log Result: {
“message”: “Queued. Thank you.”,
“id”: “<20140422121333.32180.12028@sandboxed7c45b35fc04752931f87faecae4428.mai
lgun.org>”
}

Categories: Uncategorized

Using Parse.com as a Ajax caching proxy

April 21, 2014 Leave a comment

Plenty of API’s have usage restrictions, either calls per minute, or calls per day etc. But perhaps many of your users search for similar data, and that data remains static. If I’m looking data on the longitude and latitude of a town, then this data is not going to change, then “cloud” caching would be ideal. This solution is not designed for data that may change, i.e. the current weather,

I’ve decided to use Parse.com as the backend, because it has generous free usage limits, (1 milion queries per month), it’s got a Javascript API, and it’s well known, and you can export your data if you ever wanted to move to another system.

So, lets take a simple ajax get request, in the form $.get(url, callback) and write a function with the same signature 

function cachedAjaxGet(url,callback)
{
var query = new Parse.Query(AjaxCache);
query.equalTo(“url”, url);
query.first({
success: function(object) {
if (object == undefined)
{
console.log(“cache-miss”);
$.get(url,function(data)
{
var ajaxCache = new AjaxCache();
ajaxCache.save({data: JSON.stringify(data), url: url},
{
success: function(object)
{
console.log(“stored as ” + object.id);
}
});
callback(data);
});
}
else
{
console.log(“cache-hit”);
var result = JSON.parse(object.get(‘data’));
callback(result);
}
}});
}

Then, don’t forget to initialize parse.com as follows

Parse.initialize(“….”, “…”);
var AjaxCache = Parse.Object.extend(“AjaxCache”);

And of course, include the Parse.com library from the CDN:

<script src=”http://www.parsecdn.com/js/parse-1.2.8.min.js”></script&gt;;

 

Categories: Uncategorized

Very simple, free phonegap app crash reporting

April 21, 2014 Leave a comment

App crashes are bad. They lead to negative app reviews, and often, the user does not, or cannot describe the exact actions taken just before the app crashed.

There are plenty of good app error reporting tools out there, such as exceptional, and airbrake, but lets say, we just want to have an email whenever a Javascript app crashes on a phonegap app. We want it free, and we want it as simple as possible. – But you’d like a stack trace of the error, and a decent description. – Oh, and let’s do it without requiring server-side code.

So, I set up a free account on FormToEmail.com, pressed the generate code button, and got my user_id and form_id, then I drop this function into my app:

function sendCrashReport(message, url , linenumber, column, errorObj)
{
var stack = “”;
if(errorObj !== undefined) //so it won’t blow up in the rest of the browsers
stack = errorObj.stack;
$.post(‘http://formtoemail.com/user_forms.php&#8217;,
{
“user_id” : “……”,
“form_id” : 1,
“message” : message,
“url” : url,
“linenumber” : linenumber,
“stack”: stack
},function(data)
{
console.log(data);
});
}

Then, as close as possible to the initialisation of the page, I write the code:

window.onerror = sendCrashReport;

– Of course, this may not catch compile errors or business logic mess ups, but It’ll catch serious runtime errors that could otherwise crash your app,

Categories: Uncategorized

AngularJS and BlackBerry 10 Webworks

April 21, 2014 4 comments

webinspector
AngularJS, and in particular, the ionic framework is a great way to develop Javascript apps, with best-practices baked in. It gives y0u two-way data-binding out of the box, and encourages you to separate logic and display, as well as keeping the global namespace clean. – So, I decided to give it a go, and develop an app using the ionic framework, which is based on AngularJS.

So, after getting it up and running on iOS and Android, after a few tweaks, my last platform was BlackBerry, and when firing it up on the simulator, I was disappointed to see that I couldn’t click on any of the links on the list; which was a simple rendering as follows:

 

<ion-list>
<ion-item ng-repeat=”item in data” type=”item-text-wrap” href=”#/tab/company/{{item.cacheId}}”>
{{item.title}}
</ion-item>
</ion-list>

Nothing special there, and there was no sign of the bug in Chrome, so I couldn’t debug it locally. I needed a way to debug it directly on the device. Then I remembered the remote web inspector. I’d heard of it, but never used it.

Firstly, to enable it, open the browser on the Z10 emulator, and press … => settings => developer tools => web inspector => ON. It shows a IP address, and port, you type this into any webkit browser on the same local network, and then select your application from the list.

When using bbwp to build your bar file, use the -d switch to enable remote web inspector.

You can then see console.log output, and run jquery commands against the UI. I ran the command $(“.item-content”) to see how  AngularJS had rendered the list, and I saw the problem immediately. AngularJS had “sanitized” the URL links like so href=”unsafe:local://index.htm#…” which meant that they would be blocked. The solution I found to this, could be improved, but it worked for me:

setTimeout(function () {
console.log(“SearchResultCtrl – Desanitizing… BB10 requirement”);
$( “.item-content” ).each( function( index, element ){
$(this).attr(“href”,$(this).attr(“ng-href”));
});
}, 2000);

And, then when I re-built and deployed the app back on the z10 simulator, it worked like a charm.

In hindsight, perhaps in future, I’ll just wrap my android APKs to run on the BB10 devices, but for the moment, I’m still going to stick with Webworks.

 

Categories: Uncategorized

Under the hood InAppBrowser for Cordova 3.5.0 (Phonegap)

April 19, 2014 2 comments

In previous versions of Phonegap/Cordova (i.e. 2.x), the InAppBrowser was baked into Cordova.js proper, and was not considered a plugin, it was simply called via “Window.open”, and you got Phonegap’s ‘augmented’ version of the browser control.

However, after upgrading a project to Cordova 3.5.0, the inAppBrowser baffled me, since, although window.open was still working, it wasn’t using the inAppBrowser, so therefore, once window.open was called, the user had left the app, and was then on the web.

Anyway, I finally figured out that you needed to download the InAppBrowser as a plugin. Copy the js files into the src folder (talking about Android here), a couple of images for the forward and back button, and a js file into the www folder.

However that *bloody* js file didn’t work, not sure why, but calls to “require” and “modules”, were simply not there, so, since it was a short file, I decided to pick it apart, and just use the little functionality I required from it.

Now, I’m not advocating this approach, just if you can’t face it any longer, this hack may save you alot of time.

So, instead of Window.open(url, … ), I use a new function AltWindowOpen as follows:

function altWindowOpen(strUrl, strWindowName, strWindowFeatures)
{
console.error(“altWindowOpen()”);
var cb = function(event) {
console.error(“inappBrowser – ” + event.type);
if(event.type == “loadstart”)
{
browserRef_loadstart(event);
}
};
cordova.exec(cb, cb, “InAppBrowser”, “open”, [strUrl, strWindowName, strWindowFeatures]);
}

As you see, I’m only interested in the “loadstart” event, and I want to call browserRef_loadstart() whever that happens. The event object has the property “event.url” so you can see what it’s loaded.

In order to close the browser, you call

cordova.exec(null, null, “InAppBrowser”, “close”, []);

I’ve used console.error instead of console.log so it shows up in logcat more visibly. – Just another trick I discovered tonight.

Categories: Uncategorized

Google Search API (Single site)

April 18, 2014 Leave a comment

The Google search API is only really useful for searching one site, or a list of related sites. It also has a stingy limit of 100 queries per day, so I guess, Google isn’t really making it easy for people to use it.

Anyway, if those caveats are acceptable, then here’s some code that can be used to query Google in JSON format, once again, this code is designed for Phonegap – or similar trusted environments.

function GoogleSearch(query,callback)
{
var strUrl = “https://www.googleapis.com/customsearch/v1?&#8221;;
strUrl += “q=” +encodeURIComponent(query);
strUrl+= “&cx=xxxxxx&key=xxxxxxx”;
$.get(strUrl,function(data)
{
console.log(data);
callback(data);
});
}

The callback from this function can be rendered simply using mustache thus:

<div id=”results”></div>
<script id=”resultsTpl” type=”text/template”>
{{#items}}
<a href=”{{link}}”>{{title}}</a><br>
{{/items}}
</script>

Of course, there’s plenty more data there, but all I needed was the link and title.

Categories: Uncategorized