Phonegap and Windows Phone 7: IndexOutOfBoundsException - windows-phone-8

I am having issues moving a phonegap application from Android and iOS to WP8. It seems to be crashing when I try to load some language .JSON files. The versions that I use are phonegap 2.9.0 and jQuery 2.0.3. Everything is working as intended on Android and iOS.
Console output:
'TaskHost.exe' (CLR C:\windows\system32\coreclr.dll: Silverlight AppDomain): Loaded 'C:\windows\system32\System.Runtime.Serialization.ni.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
Updating IsolatedStorage for APP:DeviceID :: ********-****-****-****-***********
CordovaBrowser_Navigated :: www/index.html
CommandString : Device/getDeviceInfo/Device899915039/[]
'TaskHost.exe' (CLR C:\windows\system32\coreclr.dll: Silverlight AppDomain): Loaded 'C:\windows\system32\System.ServiceModel.Web.ni.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'TaskHost.exe' (CLR C:\windows\system32\coreclr.dll: Silverlight AppDomain): Loaded 'C:\windows\system32\en-US\mscorlib.debug.resources.dll'. Module was built without symbols.
CommandString : NetworkStatus/getConnectionInfo/NetworkStatus899915040/[]
An exception of type 'System.NotSupportedException' occurred in Microsoft.Phone.ni.dll and wasn't handled before a managed/native boundary
The thread 0x1160 has exited with code 259 (0x103).
The thread 0x80c has exited with code 259 (0x103).
CommandString : DebugConsole/log/DebugConsole899915041/"Received Event: deviceready"
Log:["Received Event: deviceready","DebugConsole899915041"]
The thread 0x8c8 has exited with code 259 (0x103).
CommandString : File/readResourceAsText/File899915042/["localization/nb-NO.json"]
A first chance exception of type 'System.IndexOutOfRangeException' occurred in no.visma.patentstyret.DLL
An exception of type 'System.IndexOutOfRangeException' occurred in no.visma.patentstyret.DLL but was not handled in user code
This is the ajax loading of the language files:
var _loadDataSet = function(callback) {
$.ajax({url: "localization/" + _language + ".json", async: false, dataType: 'json', success: function(data) {
_dataSet = data;
if(callback) {
callback();
}
}}).error(function(e) {
console.error("Error in language files.");
console.error(e);
});
};
I have no idea where to start, any help would be much appreciated!

Show please your reading from file code.
I was making application with mustache templating engine, and did this:
$.Mustache.load("./templates/about/about-app.tpl")
This didn't load because WP8 requres full path:
$.Mustache.load("www/templates/about/about-app.tpl")
By the way, WP7 - doesn't load with full path, only with relative =)))
And another thing:
$.ajax({url: "www/localization/" + _language + ".json", async: false, dataType: 'json', success: function(data) {
WP projects don't like extensions like json and others ( sometimes it did work, sometimes didn't NO IDEA WHY ), so i suggest you do:
1) Change file type to *.txt
2) Request:
$.ajax({url: "www/localization/" + _language + ".txt", async: false, dataType: 'text', success: function(data) {
UPDATE:
Almost forgot, to use AJAX you must do this:
document.addEventListener('deviceready', function() {
jQuery.support.cors = true;
$.mobile.allowCrossDomainPages = true;
}, false);

The solution was to use XMLHttpRequest. Tested and works on Android, iPhone and Windows Phone 8. While the solution for loading the local language files was to add the data to a JavaScript class, there were still problems with cross domain requests with PhoneGap on WP8.
To achieve cross domain requests on WP8, I used XMLHttpRequests(Could also use JSONP, but this also supports other formats). This is the wrapper class that I ended up using:
(function() {
name.of.package.HTTPRequest = function(destination, success, error, contentType) {
var STATUS_IDLE = 0;
var STATUS_OPEN = 1;
var STATUS_LOADED = 2;
var STATUS_WORKING = 3;
var STATUS_DONE = 4;
var req = new XMLHttpRequest();
req.open('GET', destination, true);
if(contentType) {
req.setRequestHeader("Content-Type", contentType);
}
else {
req.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
}
req.onreadystatechange = function(aEvt) {
if(req.readyState == STATUS_DONE) {
if(req.status == 200) {
if(success) {
success(req.responseText);
}
}
else {
if(error) {
error("Response returned with error code: " + req.status);
}
}
}
};
req.send(null);
};
}) ();

Related

PWA: Chrome warning "Service worker does not have the 'fetch' handler"

I'm currently unsuccessfully trying to make my PWA installable. I have registered a SertviceWorker and linked a manifest as well as I am listening on the beforeInstallPromt event.
My ServiceWorker is listening to any fetch event.
My problem is, that the created beforeInstall banner is just being shown on Chrome desktop but on mobile I get a warning in Chrome inspection tab "Application" in the "Manifest" section:
Installability
Service worker does not have the 'fetch' handler
You can check the message on https://dev.testapp.ga/
window.addEventListener('beforeinstallprompt', (e) => {
// Stash the event so it can be triggered later.
deferredPrompt = e;
mtShowInstallButton();
});
manifest.json
{"name":"TestApp","short_name":"TestApp","start_url":"https://testapp.ga/loginCheck","icons":[{"src":"https://testapp.ga/assets/icons/launcher-ldpi.png","sizes":"36x36","density":0.75},{"src":"https://testapp.ga/assets/icons/launcher-mdpi.png","sizes":"48x48","density":1},{"src":"https://testapp.ga/assets/icons/launcher-hdpi.png","sizes":"72x72","density":1.5},{"src":"https://testapp.ga/assets/icons/launcher-xhdpi.png","sizes":"96x96","density":2},{"src":"https://testapp.ga/assets/icons/launcher-xxhdpi.png","sizes":"144x144","density":3},{"src":"https://testapp.ga/assets/icons/launcher-xxxhdpi.png","sizes":"192x192","density":4},{"src":"https://testapp.ga/assets/icons/launcher-web.png","sizes":"512x512","density":10}],"display":"standalone","background_color":"#ffffff","theme_color":"#0288d1","orientation":"any"}
ServiceWorker:
//This array should NEVER contain any file which doesn't exist. Otherwise no single file can be cached.
var preCache=[
'/favicon.png',
'/favicon.ico',
'/assets/Bears/bear-standard.png',
'/assets/jsInclude/mathjax.js',
'/material.js',
'/main.js',
'functions.js',
'/material.css',
'/materialcolors.css',
'/user.css',
'/translations.json',
'/roboto.css',
'/sw.js',
'/'
];
//Please specify the version off your App. For every new version, any files are being refreched.
var appVersion="v0.2.1";
//Please specify all files which sould never be cached
var noCache=[
'/api/'
];
//On installation of app, all files from preCache are being stored automatically.
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(appVersion+'-offline').then(function(cache) {
return cache.addAll(preCache).then(function(){
console.log('mtSW: Given files were successfully pre-cached')
});
})
);
});
function shouldCache(url) {
//Checking if url is market as noCache
var isNoCache=noCache.includes(url.substr(8).substr(url.substr(8).indexOf("/")))||noCache.includes((url.substr(8).substr(url.substr(8).indexOf("/"))).substr(0,(url.substr(8).substr(url.substr(8).indexOf("/"))).indexOf("?")));
//Checking of hostname of request != current hostname
var isOtherHost=url.substr(8).substr(0,url.substr(8).indexOf("/"))!=location.hostname&&url.substr(7).substr(0,url.substr(7).indexOf("/"))!=location.hostname;
return((url.substr(0,4)=="http"||url.substr(0,3)=="ftp") && isNoCache==false && isOtherHost==false);
}
//If any fetch fails, it will look for the request in the cache and serve it from there first
self.addEventListener('fetch', function(event) {
//Trying to answer with "online" version if fails, using cache.
event.respondWith(
fetch(event.request).then(function (response) {
if(shouldCache(response.url)) {
console.log('mtSW: Adding file to cache: '+response.url);
caches.open(appVersion+'-offline').then(function(cache) {
cache.add(new Request(response.url));
});
}
return(response);
}).catch(function(error) {
console.log( 'mtSW: Error fetching. Serving content from cache: ' + error );
//Check to see if you have it in the cache
//Return response
//If not in the cache, then return error page
return caches.open(appVersion+'-offline').then(function (cache) {
return cache.match(event.request).then(function (matching) {
var report = !matching || matching.status == 404?Promise.reject('no-match'): matching;
return report
});
});
})
);
})
I checked the mtShowInstallButton function. It's fully working on desktop.
What does this mean? On the Desktop, I never got this warning, just when using a handheld device/emulator.
Fetch function is used to fetch JSon manifest file. Try reading google docs again.
For adding PWA in Mobile you need manifest file to be fetched which is fetched using service-worker using fetch function.
Here is the code :
fetch('examples/example.json')
.then(function(response) {
// Do stuff with the response
})
.catch(function(error) {
console.log('Looks like there was a problem: \n', error);
});
for more about fetch and manifest try this.

Save Video.js recorder video on the server

I am trying to save Video recorded through Video.js to save on server, below is my code
<script>
var player = videojs("myVideo",
{
controls: true,
width: 320,
height: 240,
plugins: {
record: {
audio: true,
video: true,
maxLength: 41,
debug: true
}
}
});
player.on('startRecord', function()
{
console.log('started recording!');
});
player.on('finishRecord', function()
{
console.log('finished recording: ', player.recordedData);
});
function uploadFunction()
{
**//WRITE CODE TO SAVE player.recordedData.video in specified folder//**
}
</script>
Live Implementation : https://www.propertybihar.com/neo/videxp1/index.html
I was going through one the previously asked question, dint worked for me
How can javascript upload a blob?
If you scroll down to the "Upload" section on the README, you'll see this code snipped that does what you want, except for a streaming application:
var segmentNumber = 0;
player.on('timestamp', function() {
if (player.recordedData && player.recordedData.length > 0) {
var binaryData = player.recordedData[player.recordedData.length - 1];
segmentNumber++;
var formData = new FormData();
formData.append('SegmentNumber', segmentNumber);
formData.append('Data', binaryData);
$.ajax({
url: '/api/Test',
method: 'POST',
data: formData,
cache: false,
processData: false,
contentType: false,
success: function (res) {
console.log("segment: " + segmentNumber);
}
});
}
});
That is configured for continuously uploading the data but I've found I've had to make a few changes to it for my own setup:
On Chrome 64 with VideoJS 6.7.3 and VideoJS-Record 2.1.2 it seems that player.recordedData is not an array but just a blob.
I wanted to upload the video at a particular time, not streaming so I trigger the upload myself.
As a result, my upload code looks something like this:
if (player.recordedData) {
var binaryData = player.recordedData.video;
// ... Rest of that FormData and $.ajax snippet from previous snippet
}
If I don't do it this way, that check for existing data to upload always fails. I also trigger this code manually, rather than attaching it to the "timestamp" event of the player object. Of course, you'll need to have server side code that will accept this upload.

gulp-protractor error with chrome v54 / web driver v2.25

Due to the latest update of chrome (v54) we've noticed our protractor tests failing. We attempted to update to the latest version of gulp-protractor (v3.0.0) which in turn downloads the latest web driver (v2.25) to resolve the issue but unfortunately a new error occurs we've been unable to resolve.
Everything worked fine before chrome's update.
Our protractor configuration is as follows:
exports.config = {
// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'chrome'
},
onPrepare: function () {
var fs = require('fs');
var testDir = 'testresults/';
if (!fs.existsSync(testDir)) {
fs.mkdirSync(testDir);
}
var jasmineReporters = require('jasmine-reporters');
// returning the promise makes protractor wait for the reporter config before executing tests
return browser.getProcessedConfig().then(function () {
// you could use other properties here if you want, such as platform and version
var browserName = 'browser';
browser.getCapabilities().then(function (caps) {
browserName = caps.caps_.browserName.replace(/ /g, "_");
var junitReporter = new jasmineReporters.JUnitXmlReporter({
consolidateAll: true,
savePath: testDir,
// this will produce distinct xml files for each capability
filePrefix: 'test-protractor-' + browserName,
modifySuiteName: function (generatedSuiteName) {
// this will produce distinct suite names for each capability,
// e.g. 'firefox.login tests' and 'chrome.login tests'
return 'test-protractor-' + browserName + '.' + generatedSuiteName;
}
});
jasmine.getEnv().addReporter(junitReporter);
});
});
},
baseUrl: 'http://localhost:3000',
// Spec patterns are relative to the current working directory when
// protractor is called.
specs: [paths.e2e + '/**/*.js'],
// Options to be passed to Jasmine-node.
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000
}
};
The error is:
[13:27:13] E/launcher - Error: Error
at C:\ws\node_modules\protractor\built\util.js:55:37
at _rejected (C:\ws\node_modules\q\q.js:844:24)
at C:\ws\node_modules\q\q.js:870:30
at Promise.when (C:\ws\node_modules\q\q.js:1122:31)
at Promise.promise.promiseDispatch (C:\ws\node_modules\q\q.js:788:41)
at C:\ws\node_modules\q\q.js:604:44
at runSingle (C:\ws\node_modules\q\q.js:137:13)
at flush (C:\ws\node_modules\q\q.js:125:13)
at nextTickCallbackWith0Args (node.js:420:9)
at process._tickCallback (node.js:349:13)
[13:27:13] E/launcher - Process exited with error code 100
onPrepare is being evaluated in built/util.js in the runFilenameOrFn_ function. The stacktrace unfortunately is not helpful but what this means is that onPrepare has errors. Looking at your onPrepare method, the error is made when assigning the browserName from the browser capabilities. In your code, caps.caps_ is actually undefined. Because caps.caps_ is undefined, caps.caps_.browserName is throwing an error. The capabilities object should be accessed as the following:
browser.getCapabilities().then(capabilities => {
let browserName = capabilities.browserName.replace(/ /g, "_");

Submit form without opening browser in Windows 8

I'm building an app using Microsoft's new HTMl5 framework for Metro apps. I've created a form that I use to submit GET data. The problem is, clicking the "Run Query" (Submit) button on the app opens a browser window. What are some ways that I can submit the data in the GET method without opening a browser window.
I've tried using jQuery to do so but with little yield. It throws the message "jQuery" is not defined.
Is there any HTML I can use, or, better yet, something I can add into default.js?
As requested, jQuery I'm using:
jQuery(document).ready(function () {
jQuery('.ajaxform').submit(function () {
$.ajax({
url: $(this).attr('action'),
type: $(this).attr('method'),
dataType: 'json',
data: $(this).serialize(),
success: function (data) {
for (var id in data) {
jQuery('#' + id).html(data[id]);
}
}
});
return false;
});
});
Get the values from your form, save it in an object, encode it using javascript function and use xhr,
Get form values using js, say
var b=document.getElementById(textboxname).value;
var params={
parameter:b,
}
In order to encode your parameters you can use the following javascript function,
function formatParams(y) {
var queryStr = "";
for (var propertyName in y) {
var val = y[propertyName];
queryStr += propertyName + "=" + encodeURI(val) + "&";
}
return queryStr.slice(0, -1);
}
Call your web service using WinJS.xhr
WinJS.xhr({
type: "get/post",
url: "your URL",
data: formatParams(params),
headers: { "Content-type": "application/x-www-form-urlencoded" }
}).done(function (response) {
var json = JSON.parse(response.responseText);
//process accordingly
}
Im assuming you are getting JSON response from your web service.
I'm guessing here you are referring to an external script for jQuery.
Since winjs is running under different security restrictions than a typical web app in a browser your scripts must be local.
Since you are already using jquery - assuming version 2.0 or greater which is Win8/winjs compatible - make sure you have included a reference to jquery LOCALLY in your project and NOT from an external website, you can just use $(document) instead of jQuery(document).
ie:
<script src="/scripts/jquery-2.0.0.js" /> (or whatever your version is)
and make sure you have the files locally. You can just go in Visual Studio to Tools->Library Package Manager->Package Manager Console and type in
install-package jquery

peerConnection.addIceCandidate giving error: invalid string

I am trying to implement a Voice-only WebRTC app. I am running it on Chrome Version 29.0.1547.0 dev. My app uses Socket.IO for the signaling mechanism.
peerConnection.addIceCandidate() is giving me this error: Uncaught SyntaxError: An invalid or illegal string was specified.
and separately, peerConnection.setRemoteDescription(); is giving me this error: Uncaught TypeMismatchError: The type of an object was incompatible with the expected type of the parameter associated to the object.
Here's my code:
SERVER (in CoffeeScript)
app = require("express")()
server = require("http").createServer(app).listen(3000)
io = require("socket.io").listen(server)
app.get "/", (req, res) -> res.sendfile("index.html")
app.get "/client.js", (req, res) -> res.sendfile("client.js")
io.sockets.on "connection", (socket) ->
socket.on "message", (data) ->
socket.broadcast.emit "message", data
CLIENT (in JavaScript)
var socket = io.connect("http://localhost:3000");
var pc = new webkitRTCPeerConnection({
"iceServers": [{"url": "stun:stun.l.google.com:19302"}]
});
navigator.getUserMedia = navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia;
navigator.getUserMedia({audio: true}, function (stream) {
pc.addStream(stream);
}, function (error) { console.log(error); });
pc.onicecandidate = function (event) {
if (!event || !event.candidate) return;
socket.emit("message", {
type: "iceCandidate",
"candidate": event.candidate
});
};
pc.onaddstream = function(event) {
var audioElem = document.createElement("audio");
audioElem.src = webkitURL.createObjectURL(event.stream);
audioElem.autoplay = true;
document.appendChild(audioElem);
console.log("Got Remote Stream");
};
socket.on("message", function(data) {
if (data.type === "iceCandidate") {
console.log(data.candidate);
candidate = new RTCIceCandidate(data.candidate);
console.log(candidate);
pc.addIceCandidate(candidate);
} else if (data.type === "offer") {
pc.setRemoteDescription(data.description);
pc.createAnswer(function(description) {
pc.setLocalDescription(description);
socket.emit("message", {type: "answer", description: description});
});
} else if (data.type === "answer") {
pc.setRemoteDescription(data.description);
}
});
function offer() {
pc.createOffer( function (description) {
pc.setLocalDescription(description);
socket.emit("message", {type: "offer", "description": description});
});
};
The HTML just contains a button that calls offer().
I can confirm the ICECandidates and SessionDescriptions are transferring successfully from one client to the other.
What am I doing wrong? And how should I fix these and any other errors so that I can transfer audio from one client to the other?
PS: If you know about a good source documenting the WebRTC API (except the W3C documentation), please tell me about it!
Thanks!
For that error the point is, ICE Candidates must be added only after successfully setting remote description.
Note that just after creating Offer (by Offerer), ice candidates are produced immediately. So, if somehow the answerer receives those candidates, before setting remote description (which in theory would arrive before candidates), you get error.
The same is true for offerer. It must set remote description before adding any ice candidate.
I see that in your javascript code you are not guaranteeing that remote description is set before adding ice candidates.
First of all you can check just before pc.addIceCandidate(candidate); if pc's remoteDescription is set. If you see that it is null (or undefined), you can locally store received ice candidates to add them after setting remoteDescription (or wait in offerer to send them in proper time.)